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   // When isTest is true, skip non-hermetic code.
mIsTest(isTest)92   NetworkTraceHandler(bool isTest = false) : mIsTest(isTest) {}
93 
94   // perfetto::DataSource overrides:
95   void OnSetup(const SetupArgs& args) override;
96   void OnStart(const StartArgs&) override;
97   void OnStop(const StopArgs&) override;
98 
99   // Writes the packets as Perfetto TracePackets, creating packets as needed
100   // using the provided callback (which allows easy testing).
101   void Write(const std::vector<PacketTrace>& packets,
102              NetworkTraceHandler::TraceContext& ctx);
103 
104  private:
105   // Fills in contextual information from a bundle without interning.
106   void Fill(const BundleKey& src,
107             ::perfetto::protos::pbzero::NetworkPacketEvent* event);
108 
109   // Fills in contextual information either inline or via interning.
110   ::perfetto::protos::pbzero::NetworkPacketBundle* FillWithInterning(
111       NetworkTraceState* state, const BundleKey& src,
112       ::perfetto::protos::pbzero::TracePacket* dst);
113 
114   static internal::NetworkTracePoller sPoller;
115   bool mStarted;
116   bool mIsTest;
117 
118   // Values from config, see proto for details.
119   uint32_t mPollMs;
120   uint32_t mInternLimit;
121   uint32_t mAggregationThreshold;
122   bool mDropLocalPort;
123   bool mDropRemotePort;
124   bool mDropTcpFlags;
125 };
126 
127 }  // namespace bpf
128 }  // namespace android
129