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