• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <linux/if.h>
20 #include <linux/if_ether.h>
21 #include <linux/in.h>
22 #include <linux/in6.h>
23 
24 #ifdef __cplusplus
25 #include <string_view>
26 #include "XtBpfProgLocations.h"
27 #endif
28 
29 // This header file is shared by eBPF kernel programs (C) and netd (C++) and
30 // some of the maps are also accessed directly from Java mainline module code.
31 //
32 // Hence: explicitly pad all relevant structures and assert that their size
33 // is the sum of the sizes of their fields.
34 #define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
35 
36 typedef struct {
37     uint32_t uid;
38     uint32_t tag;
39 } UidTagValue;
40 STRUCT_SIZE(UidTagValue, 2 * 4);  // 8
41 
42 typedef struct {
43     uint32_t uid;
44     uint32_t tag;
45     uint32_t counterSet;
46     uint32_t ifaceIndex;
47 } StatsKey;
48 STRUCT_SIZE(StatsKey, 4 * 4);  // 16
49 
50 typedef struct {
51     uint64_t rxPackets;
52     uint64_t rxBytes;
53     uint64_t txPackets;
54     uint64_t txBytes;
55 } StatsValue;
56 STRUCT_SIZE(StatsValue, 4 * 8);  // 32
57 
58 typedef struct {
59     char name[IFNAMSIZ];
60 } IfaceValue;
61 STRUCT_SIZE(IfaceValue, 16);
62 
63 typedef struct {
64     uint64_t rxBytes;
65     uint64_t rxPackets;
66     uint64_t txBytes;
67     uint64_t txPackets;
68     uint64_t tcpRxPackets;
69     uint64_t tcpTxPackets;
70 } Stats;
71 
72 typedef struct {
73   uint64_t timestampNs;
74   uint32_t ifindex;
75   uint32_t length;
76 
77   uint32_t uid;
78   uint32_t tag;
79 
80   __be16 sport;
81   __be16 dport;
82 
83   bool egress;
84   uint8_t ipProto;
85   uint8_t tcpFlags;
86   uint8_t ipVersion; // 4=IPv4, 6=IPv6, 0=unknown
87 } PacketTrace;
88 STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1);
89 
90 // Since we cannot garbage collect the stats map since device boot, we need to make these maps as
91 // large as possible. The maximum size of number of map entries we can have is depend on the rlimit
92 // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the
93 // following fomula:
94 //      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8)
95 //      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries +
96 //              elem_size * number_of_CPU
97 // And the cost of each map currently used is(assume the device have 8 CPUs):
98 // cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes
99 // uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
100 // app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes
101 // uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
102 // tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
103 // iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes
104 // iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes
105 // dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
106 // standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
107 // powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
108 // packet_trace_ringbuf:key:  0 bytes, value: 24 bytes, cost:   32768 bytes    =    32Kbytes
109 // total:                                                                         4962Kbytes
110 // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices
111 // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module,
112 // we don't have a total limit for data entries but only have limitation of tags each uid can have.
113 // (default is 1024 in kernel);
114 
115 // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation
116 static const int COOKIE_UID_MAP_SIZE = 10000;
117 static const int UID_COUNTERSET_MAP_SIZE = 4000;
118 static const int APP_STATS_MAP_SIZE = 10000;
119 static const int STATS_MAP_SIZE = 5000;
120 static const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
121 static const int IFACE_STATS_MAP_SIZE = 1000;
122 static const int CONFIGURATION_MAP_SIZE = 2;
123 static const int UID_OWNER_MAP_SIZE = 4000;
124 static const int PACKET_TRACE_BUF_SIZE = 32 * 1024;
125 
126 #ifdef __cplusplus
127 
128 #define BPF_NETD_PATH "/sys/fs/bpf/netd_shared/"
129 
130 #define BPF_EGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_egress_stats"
131 #define BPF_INGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_ingress_stats"
132 
133 #define ASSERT_STRING_EQUAL(s1, s2) \
134     static_assert(std::string_view(s1) == std::string_view(s2), "mismatch vs Android T netd")
135 
136 /* -=-=-=-=- WARNING -=-=-=-=-
137  *
138  * These 4 xt_bpf program paths are actually defined by:
139  *   //system/netd/include/mainline/XtBpfProgLocations.h
140  * which is intentionally a non-automerged location.
141  *
142  * They are *UNCHANGEABLE* due to being hard coded in Android T's netd binary
143  * as such we have compile time asserts that things match.
144  * (which will be validated during build on mainline-prod branch against old system/netd)
145  *
146  * If you break this, netd on T will fail to start with your tethering mainline module.
147  */
148 ASSERT_STRING_EQUAL(XT_BPF_INGRESS_PROG_PATH,   BPF_NETD_PATH "prog_netd_skfilter_ingress_xtbpf");
149 ASSERT_STRING_EQUAL(XT_BPF_EGRESS_PROG_PATH,    BPF_NETD_PATH "prog_netd_skfilter_egress_xtbpf");
150 ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf");
151 ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH,  BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf");
152 
153 #define CGROUP_SOCKET_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create"
154 
155 #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account"
156 #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME
157 
158 #define COOKIE_TAG_MAP_PATH BPF_NETD_PATH "map_netd_cookie_tag_map"
159 #define UID_COUNTERSET_MAP_PATH BPF_NETD_PATH "map_netd_uid_counterset_map"
160 #define APP_UID_STATS_MAP_PATH BPF_NETD_PATH "map_netd_app_uid_stats_map"
161 #define STATS_MAP_A_PATH BPF_NETD_PATH "map_netd_stats_map_A"
162 #define STATS_MAP_B_PATH BPF_NETD_PATH "map_netd_stats_map_B"
163 #define IFACE_INDEX_NAME_MAP_PATH BPF_NETD_PATH "map_netd_iface_index_name_map"
164 #define IFACE_STATS_MAP_PATH BPF_NETD_PATH "map_netd_iface_stats_map"
165 #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map"
166 #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map"
167 #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map"
168 #define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf"
169 #define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map"
170 
171 #endif // __cplusplus
172 
173 // LINT.IfChange(match_type)
174 enum UidOwnerMatchType {
175     NO_MATCH = 0,
176     HAPPY_BOX_MATCH = (1 << 0),
177     PENALTY_BOX_MATCH = (1 << 1),
178     DOZABLE_MATCH = (1 << 2),
179     STANDBY_MATCH = (1 << 3),
180     POWERSAVE_MATCH = (1 << 4),
181     RESTRICTED_MATCH = (1 << 5),
182     LOW_POWER_STANDBY_MATCH = (1 << 6),
183     IIF_MATCH = (1 << 7),
184     LOCKDOWN_VPN_MATCH = (1 << 8),
185     OEM_DENY_1_MATCH = (1 << 9),
186     OEM_DENY_2_MATCH = (1 << 10),
187     OEM_DENY_3_MATCH = (1 << 11),
188 };
189 // LINT.ThenChange(packages/modules/Connectivity/service/src/com/android/server/BpfNetMaps.java)
190 
191 enum BpfPermissionMatch {
192     BPF_PERMISSION_INTERNET = 1 << 2,
193     BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3,
194 };
195 // In production we use two identical stats maps to record per uid stats and
196 // do swap and clean based on the configuration specified here. The statsMapType
197 // value in configuration map specified which map is currently in use.
198 enum StatsMapType {
199     SELECT_MAP_A,
200     SELECT_MAP_B,
201 };
202 
203 // TODO: change the configuration object from a bitmask to an object with clearer
204 // semantics, like a struct.
205 typedef uint32_t BpfConfig;
206 static const BpfConfig DEFAULT_CONFIG = 0;
207 
208 typedef struct {
209     // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above.
210     uint32_t iif;
211     // A bitmask of enum values in UidOwnerMatchType.
212     uint32_t rule;
213 } UidOwnerValue;
214 STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8
215 
216 // Entry in the configuration map that stores which UID rules are enabled.
217 #define UID_RULES_CONFIGURATION_KEY 0
218 // Entry in the configuration map that stores which stats map is currently in use.
219 #define CURRENT_STATS_MAP_CONFIGURATION_KEY 1
220 
221 #undef STRUCT_SIZE
222