From 61976f278f374ba5244a9bc967bbdc3098f2f6dc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 26 Jan 2021 23:41:21 +0900 Subject: [PATCH] Dump BPF offload rules for upstream IPv4 and IPv6. Add code to BpfCoordinator to dump upstream IPv4 and IPv6 rules. For IPv4, currently only the upstream map is printed, because the downstream map is expected to be symmetrical. Example output: ============= 21(21) -> 12(rmnet_data2) 86dd 00:00:00:00:00:00 00:00:00:00:00:00 [wlan1]: iif(iface) oif(iface) v6addr srcmac dstmac 12(rmnet_data2) 21(wlan1) /2001:240:2425:b5dc:21a9:995d:bc57:bc37 b2:b5:e0:24:21:c2 ca:06:8d:54:99:ad [IPv4]: iif(iface) oif(iface) src nat dst 21(21) 12(rmnet_data2) 192.168.16.247:41544 -> 100.101.80.108:41544 -> 216.239.36.135:443 21(21) 12(rmnet_data2) 192.168.16.247:42028 -> 100.101.80.108:42028 -> 8.8.4.4:853 21(21) 12(rmnet_data2) 192.168.16.247:42032 -> 100.101.80.108:42032 -> 8.8.4.4:853 21(21) 12(rmnet_data2) 192.168.16.247:42042 -> 100.101.80.108:42042 -> 8.8.4.4:853 21(21) 12(rmnet_data2) 192.168.16.247:41816 -> 100.101.80.108:41816 -> 8.8.8.8:853 21(21) 12(rmnet_data2) 192.168.16.247:42040 -> 100.101.80.108:42040 -> 8.8.4.4:853 ============= Also make it possible to do "dumpsys tethering bpf" and get only the BPF dump. Test: manual Change-Id: I2aaa2fdda7d724994090c26feff585f24cd3283b --- .../apishim/api31/BpfCoordinatorShimImpl.java | 24 +++--- .../tethering/BpfCoordinator.java | 77 +++++++++++++++++-- .../networkstack/tethering/Tethering.java | 17 +++- 3 files changed, 97 insertions(+), 21 deletions(-) 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 2bdddc11b3..4dc1c51f68 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 @@ -324,20 +324,20 @@ public class BpfCoordinatorShimImpl return true; } + private String mapStatus(BpfMap m, String name) { + return name + "{" + (m != null ? "OK" : "ERROR") + "}"; + } + @Override public String toString() { - return "mBpfDownstream4Map{" - + (mBpfDownstream4Map != null ? "initialized" : "not initialized") + "}, " - + "mBpfUpstream4Map{" - + (mBpfUpstream4Map != null ? "initialized" : "not initialized") + "}, " - + "mBpfUpstream6Map{" - + (mBpfUpstream6Map != null ? "initialized" : "not initialized") + "}, " - + "mBpfDownstream6Map{" - + (mBpfDownstream6Map != null ? "initialized" : "not initialized") + "}, " - + "mBpfStatsMap{" - + (mBpfStatsMap != null ? "initialized" : "not initialized") + "}, " - + "mBpfLimitMap{" - + (mBpfLimitMap != null ? "initialized" : "not initialized") + "} "; + return String.join(", ", new String[] { + mapStatus(mBpfDownstream6Map, "mBpfDownstream6Map"), + mapStatus(mBpfUpstream6Map, "mBpfUpstream6Map"), + mapStatus(mBpfDownstream4Map, "mBpfDownstream4Map"), + mapStatus(mBpfUpstream4Map, "mBpfUpstream4Map"), + mapStatus(mBpfStatsMap, "mBpfStatsMap"), + mapStatus(mBpfLimitMap, "mBpfLimitMap") + }); } /** diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 35de4003ea..b17bfcf8af 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -64,6 +64,7 @@ import com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -677,6 +678,12 @@ public class BpfCoordinator { } } + + // TODO: make mInterfaceNames accessible to the shim and move this code to there. + private String getIfName(long ifindex) { + return mInterfaceNames.get((int) ifindex, Long.toString(ifindex)); + } + /** * Dump information. * Block the function until all the data are dumped on the handler thread or timed-out. The @@ -705,11 +712,9 @@ public class BpfCoordinator { pw.println("Forwarding rules:"); pw.increaseIndent(); - if (mIpv6ForwardingRules.size() == 0) { - pw.println(""); - } else { - dumpIpv6ForwardingRules(pw); - } + dumpIpv6UpstreamRules(pw); + dumpIpv6ForwardingRules(pw); + dumpIpv4ForwardingRules(pw); pw.decreaseIndent(); dumpDone.open(); @@ -729,6 +734,11 @@ public class BpfCoordinator { } private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) { + if (mIpv6ForwardingRules.size() == 0) { + pw.println("No IPv6 rules"); + return; + } + for (Map.Entry> entry : mIpv6ForwardingRules.entrySet()) { IpServer ipServer = entry.getKey(); @@ -749,6 +759,63 @@ public class BpfCoordinator { } } + private String ipv6UpstreamRuletoString(TetherUpstream6Key key, Tether6Value value) { + return String.format("%d(%s) -> %d(%s) %04x %s %s", + key.iif, getIfName(key.iif), value.oif, getIfName(value.oif), + value.ethProto, value.ethSrcMac, value.ethDstMac); + } + + private void dumpIpv6UpstreamRules(IndentingPrintWriter pw) { + final BpfMap ipv6UpstreamMap = mDeps.getBpfUpstream6Map(); + if (ipv6UpstreamMap == null) { + pw.println("No IPv6 upstream"); + return; + } + try { + if (ipv6UpstreamMap.isEmpty()) { + pw.println("No IPv6 upstream rules"); + return; + } + ipv6UpstreamMap.forEach((k, v) -> pw.println(ipv6UpstreamRuletoString(k, v))); + } catch (ErrnoException e) { + pw.println("Error dumping IPv4 map: " + e); + } + } + + private String ipv4RuleToString(Tether4Key key, Tether4Value value) { + final String private4, public4, dst4; + try { + private4 = InetAddress.getByAddress(key.src4).getHostAddress(); + dst4 = InetAddress.getByAddress(key.dst4).getHostAddress(); + public4 = InetAddress.getByAddress(value.src46).getHostAddress(); + } catch (UnknownHostException impossible) { + throw new AssertionError("4-byte array not valid IPv4 address!"); + } + return String.format("%d(%s) %d(%s) %s:%d -> %s:%d -> %s:%d", + key.iif, getIfName(key.iif), value.oif, getIfName(value.oif), + private4, key.srcPort, public4, value.srcPort, dst4, key.dstPort); + } + + private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) { + final BpfMap ipv4UpstreamMap = mDeps.getBpfUpstream4Map(); + if (ipv4UpstreamMap == null) { + pw.println("No IPv4 support"); + return; + } + try { + if (ipv4UpstreamMap.isEmpty()) { + pw.println("No IPv4 rules"); + return; + } + pw.println("[IPv4]: iif(iface) oif(iface) src nat dst"); + pw.increaseIndent(); + ipv4UpstreamMap.forEach((k, v) -> pw.println(ipv4RuleToString(k, v))); + } catch (ErrnoException e) { + pw.println("Error dumping IPv4 map: " + e); + } + pw.decreaseIndent(); + } + /** IPv6 forwarding rule class. */ public static class Ipv6ForwardingRule { public final int upstreamIfindex; diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 2354c2d2ed..385c691025 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -2225,6 +2225,13 @@ public class Tethering { && !isProvisioningNeededButUnavailable(); } + private void dumpBpf(IndentingPrintWriter pw) { + pw.println("BPF offload:"); + pw.increaseIndent(); + mBpfCoordinator.dump(pw); + pw.decreaseIndent(); + } + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") @@ -2235,6 +2242,11 @@ public class Tethering { return; } + if (argsContain(args, "bpf")) { + dumpBpf(pw); + return; + } + pw.println("Tethering:"); pw.increaseIndent(); @@ -2286,10 +2298,7 @@ public class Tethering { mOffloadController.dump(pw); pw.decreaseIndent(); - pw.println("BPF offload:"); - pw.increaseIndent(); - mBpfCoordinator.dump(pw); - pw.decreaseIndent(); + dumpBpf(pw); pw.println("Private address coordinator:"); pw.increaseIndent();