1 /** 2 * Copyright (c) 2023, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <perfetto/base/task_runner.h> 20 #include <perfetto/tracing.h> 21 22 #include <string> 23 #include <unordered_map> 24 25 #include "netdbpf/NetworkTracePoller.h" 26 27 // For PacketTrace struct definition 28 #include "netd.h" 29 30 namespace android { 31 namespace bpf { 32 33 // BundleKey encodes a PacketTrace minus timestamp and length. The key should 34 // match many packets over time for interning. For convenience, sport/dport 35 // are parsed here as either local/remote port or icmp type/code. 36 struct BundleKey { 37 explicit BundleKey(const PacketTrace& pkt); 38 39 uint32_t ifindex; 40 uint32_t uid; 41 uint32_t tag; 42 43 bool egress; 44 uint8_t ipProto; 45 uint8_t ipVersion; 46 47 std::optional<uint8_t> tcpFlags; 48 std::optional<uint16_t> localPort; 49 std::optional<uint16_t> remotePort; 50 std::optional<uint8_t> icmpType; 51 std::optional<uint8_t> icmpCode; 52 }; 53 54 // BundleKeys are hashed using a simple hash combine. 55 struct BundleHash { 56 std::size_t operator()(const BundleKey& a) const; 57 }; 58 59 // BundleKeys are equal if all fields are equal. 60 struct BundleEq { 61 bool operator()(const BundleKey& a, const BundleKey& b) const; 62 }; 63 64 // Track the bundles we've interned and their corresponding intern id (iid). We 65 // use IncrementalState (rather than state in the Handler) so that we stay in 66 // sync with Perfetto's periodic state clearing (which helps recover from packet 67 // loss). When state is cleared, the state object is replaced with a new default 68 // constructed instance. 69 struct NetworkTraceState { 70 bool cleared = true; 71 std::unordered_map<BundleKey, uint64_t, BundleHash, BundleEq> iids; 72 }; 73 74 // Inject our custom incremental state type using type traits. 75 struct NetworkTraceTraits : public perfetto::DefaultDataSourceTraits { 76 using IncrementalStateType = NetworkTraceState; 77 }; 78 79 // NetworkTraceHandler implements the android.network_packets data source. This 80 // class is registered with Perfetto and is instantiated when tracing starts and 81 // destroyed when tracing ends. There is one instance per trace session. 82 class NetworkTraceHandler 83 : public perfetto::DataSource<NetworkTraceHandler, NetworkTraceTraits> { 84 public: 85 // Registers this DataSource. 86 static void RegisterDataSource(); 87 88 // Connects to the system Perfetto daemon and registers the trace handler. 89 static void InitPerfettoTracing(); 90 91 // This prevents Perfetto from holding the data source lock when calling 92 // OnSetup, OnStart, or OnStop. The lock is still held by the LockedHandle 93 // returned by GetDataSourceLocked. Disabling this lock prevents a deadlock 94 // where OnStop holds this lock waiting for the poller to stop, but the poller 95 // is running the callback that is trying to acquire the lock. 96 static constexpr bool kRequiresCallbacksUnderLock = false; 97 98 // When isTest is true, skip non-hermetic code. mIsTest(isTest)99 NetworkTraceHandler(bool isTest = false) : mIsTest(isTest) {} 100 101 // perfetto::DataSource overrides: 102 void OnSetup(const SetupArgs& args) override; 103 void OnStart(const StartArgs&) override; 104 void OnStop(const StopArgs&) override; 105 106 // Writes the packets as Perfetto TracePackets, creating packets as needed 107 // using the provided callback (which allows easy testing). 108 void Write(const std::vector<PacketTrace>& packets, 109 NetworkTraceHandler::TraceContext& ctx); 110 111 private: 112 // Fills in contextual information from a bundle without interning. 113 void Fill(const BundleKey& src, 114 ::perfetto::protos::pbzero::NetworkPacketEvent* event); 115 116 // Fills in contextual information either inline or via interning. 117 ::perfetto::protos::pbzero::NetworkPacketBundle* FillWithInterning( 118 NetworkTraceState* state, const BundleKey& src, 119 ::perfetto::protos::pbzero::TracePacket* dst); 120 121 static internal::NetworkTracePoller sPoller; 122 bool mStarted; 123 bool mIsTest; 124 125 // Values from config, see proto for details. 126 uint32_t mPollMs; 127 uint32_t mInternLimit; 128 uint32_t mAggregationThreshold; 129 bool mDropLocalPort; 130 bool mDropRemotePort; 131 bool mDropTcpFlags; 132 }; 133 134 } // namespace bpf 135 } // namespace android 136