Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 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> |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 23 | |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 24 | #ifdef __cplusplus |
| 25 | #include <string_view> |
| 26 | #include "XtBpfProgLocations.h" |
| 27 | #endif |
| 28 | |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 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 | // Since we cannot garbage collect the stats map since device boot, we need to make these maps as |
| 73 | // large as possible. The maximum size of number of map entries we can have is depend on the rlimit |
| 74 | // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the |
| 75 | // following fomula: |
| 76 | // elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8) |
| 77 | // cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries + |
| 78 | // elem_size * number_of_CPU |
| 79 | // And the cost of each map currently used is(assume the device have 8 CPUs): |
| 80 | // cookie_tag_map: key: 8 bytes, value: 8 bytes, cost: 822592 bytes = 823Kbytes |
| 81 | // uid_counter_set_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes |
| 82 | // app_uid_stats_map: key: 4 bytes, value: 32 bytes, cost: 1062784 bytes = 1063Kbytes |
| 83 | // uid_stats_map: key: 16 bytes, value: 32 bytes, cost: 1142848 bytes = 1143Kbytes |
| 84 | // tag_stats_map: key: 16 bytes, value: 32 bytes, cost: 1142848 bytes = 1143Kbytes |
| 85 | // iface_index_name_map:key: 4 bytes, value: 16 bytes, cost: 80896 bytes = 81Kbytes |
| 86 | // iface_stats_map: key: 4 bytes, value: 32 bytes, cost: 97024 bytes = 97Kbytes |
| 87 | // dozable_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes |
| 88 | // standby_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes |
| 89 | // powersave_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes |
| 90 | // total: 4930Kbytes |
| 91 | // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices |
| 92 | // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module, |
| 93 | // we don't have a total limit for data entries but only have limitation of tags each uid can have. |
| 94 | // (default is 1024 in kernel); |
| 95 | |
| 96 | // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation |
| 97 | static const int COOKIE_UID_MAP_SIZE = 10000; |
t-m-w | 5fc252d | 2022-10-11 15:16:16 +0000 | [diff] [blame^] | 98 | static const int UID_COUNTERSET_MAP_SIZE = 4000; |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 99 | static const int APP_STATS_MAP_SIZE = 10000; |
| 100 | static const int STATS_MAP_SIZE = 5000; |
| 101 | static const int IFACE_INDEX_NAME_MAP_SIZE = 1000; |
| 102 | static const int IFACE_STATS_MAP_SIZE = 1000; |
| 103 | static const int CONFIGURATION_MAP_SIZE = 2; |
t-m-w | 5fc252d | 2022-10-11 15:16:16 +0000 | [diff] [blame^] | 104 | static const int UID_OWNER_MAP_SIZE = 4000; |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 105 | |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 106 | #ifdef __cplusplus |
| 107 | |
Maciej Żenczykowski | a52aca7 | 2022-05-16 13:59:12 -0700 | [diff] [blame] | 108 | #define BPF_NETD_PATH "/sys/fs/bpf/netd_shared/" |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 109 | |
Maciej Żenczykowski | a52aca7 | 2022-05-16 13:59:12 -0700 | [diff] [blame] | 110 | #define BPF_EGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_egress_stats" |
| 111 | #define BPF_INGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_ingress_stats" |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 112 | |
| 113 | #define ASSERT_STRING_EQUAL(s1, s2) \ |
Maciej Żenczykowski | ca9af17 | 2022-06-15 03:43:31 -0700 | [diff] [blame] | 114 | static_assert(std::string_view(s1) == std::string_view(s2), "mismatch vs Android T netd") |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 115 | |
| 116 | /* -=-=-=-=- WARNING -=-=-=-=- |
| 117 | * |
| 118 | * These 4 xt_bpf program paths are actually defined by: |
Maciej Żenczykowski | 70201a1 | 2022-06-15 01:06:27 -0700 | [diff] [blame] | 119 | * //system/netd/include/mainline/XtBpfProgLocations.h |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 120 | * which is intentionally a non-automerged location. |
| 121 | * |
| 122 | * They are *UNCHANGEABLE* due to being hard coded in Android T's netd binary |
| 123 | * as such we have compile time asserts that things match. |
| 124 | * (which will be validated during build on mainline-prod branch against old system/netd) |
| 125 | * |
| 126 | * If you break this, netd on T will fail to start with your tethering mainline module. |
| 127 | */ |
| 128 | ASSERT_STRING_EQUAL(XT_BPF_INGRESS_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_ingress_xtbpf"); |
| 129 | ASSERT_STRING_EQUAL(XT_BPF_EGRESS_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_egress_xtbpf"); |
| 130 | ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf"); |
| 131 | ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf"); |
| 132 | |
Maciej Żenczykowski | a52aca7 | 2022-05-16 13:59:12 -0700 | [diff] [blame] | 133 | #define CGROUP_SOCKET_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create" |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 134 | |
| 135 | #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account" |
Maciej Żenczykowski | a52aca7 | 2022-05-16 13:59:12 -0700 | [diff] [blame] | 136 | #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 137 | |
Maciej Żenczykowski | a52aca7 | 2022-05-16 13:59:12 -0700 | [diff] [blame] | 138 | #define COOKIE_TAG_MAP_PATH BPF_NETD_PATH "map_netd_cookie_tag_map" |
| 139 | #define UID_COUNTERSET_MAP_PATH BPF_NETD_PATH "map_netd_uid_counterset_map" |
| 140 | #define APP_UID_STATS_MAP_PATH BPF_NETD_PATH "map_netd_app_uid_stats_map" |
| 141 | #define STATS_MAP_A_PATH BPF_NETD_PATH "map_netd_stats_map_A" |
| 142 | #define STATS_MAP_B_PATH BPF_NETD_PATH "map_netd_stats_map_B" |
| 143 | #define IFACE_INDEX_NAME_MAP_PATH BPF_NETD_PATH "map_netd_iface_index_name_map" |
| 144 | #define IFACE_STATS_MAP_PATH BPF_NETD_PATH "map_netd_iface_stats_map" |
| 145 | #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map" |
| 146 | #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map" |
| 147 | #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map" |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 148 | |
Maciej Żenczykowski | 801154a | 2022-06-14 14:36:34 -0700 | [diff] [blame] | 149 | #endif // __cplusplus |
| 150 | |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 151 | enum UidOwnerMatchType { |
| 152 | NO_MATCH = 0, |
| 153 | HAPPY_BOX_MATCH = (1 << 0), |
| 154 | PENALTY_BOX_MATCH = (1 << 1), |
| 155 | DOZABLE_MATCH = (1 << 2), |
| 156 | STANDBY_MATCH = (1 << 3), |
| 157 | POWERSAVE_MATCH = (1 << 4), |
| 158 | RESTRICTED_MATCH = (1 << 5), |
Robert Horvath | 5442302 | 2022-01-27 19:53:27 +0100 | [diff] [blame] | 159 | LOW_POWER_STANDBY_MATCH = (1 << 6), |
| 160 | IIF_MATCH = (1 << 7), |
Motomu Utsumi | 966ff7f | 2022-05-11 05:56:26 +0000 | [diff] [blame] | 161 | LOCKDOWN_VPN_MATCH = (1 << 8), |
Motomu Utsumi | 9cd4726 | 2022-06-01 13:57:27 +0000 | [diff] [blame] | 162 | OEM_DENY_1_MATCH = (1 << 9), |
| 163 | OEM_DENY_2_MATCH = (1 << 10), |
Motomu Utsumi | 608015f | 2022-06-06 07:44:05 +0000 | [diff] [blame] | 164 | OEM_DENY_3_MATCH = (1 << 11), |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 165 | }; |
| 166 | |
| 167 | enum BpfPermissionMatch { |
| 168 | BPF_PERMISSION_INTERNET = 1 << 2, |
| 169 | BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3, |
| 170 | }; |
| 171 | // In production we use two identical stats maps to record per uid stats and |
| 172 | // do swap and clean based on the configuration specified here. The statsMapType |
| 173 | // value in configuration map specified which map is currently in use. |
| 174 | enum StatsMapType { |
| 175 | SELECT_MAP_A, |
| 176 | SELECT_MAP_B, |
| 177 | }; |
| 178 | |
Lorenzo Colitti | 90c0c3f | 2022-03-03 17:49:01 +0900 | [diff] [blame] | 179 | // TODO: change the configuration object from a bitmask to an object with clearer |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 180 | // semantics, like a struct. |
Lorenzo Colitti | 90c0c3f | 2022-03-03 17:49:01 +0900 | [diff] [blame] | 181 | typedef uint32_t BpfConfig; |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 182 | static const BpfConfig DEFAULT_CONFIG = 0; |
| 183 | |
| 184 | typedef struct { |
| 185 | // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above. |
| 186 | uint32_t iif; |
| 187 | // A bitmask of enum values in UidOwnerMatchType. |
| 188 | uint32_t rule; |
| 189 | } UidOwnerValue; |
| 190 | STRUCT_SIZE(UidOwnerValue, 2 * 4); // 8 |
| 191 | |
Lorenzo Colitti | 90c0c3f | 2022-03-03 17:49:01 +0900 | [diff] [blame] | 192 | // Entry in the configuration map that stores which UID rules are enabled. |
Maciej Żenczykowski | 9017a07 | 2022-06-16 14:49:27 -0700 | [diff] [blame] | 193 | #define UID_RULES_CONFIGURATION_KEY 0 |
Lorenzo Colitti | 90c0c3f | 2022-03-03 17:49:01 +0900 | [diff] [blame] | 194 | // Entry in the configuration map that stores which stats map is currently in use. |
Maciej Żenczykowski | 9017a07 | 2022-06-16 14:49:27 -0700 | [diff] [blame] | 195 | #define CURRENT_STATS_MAP_CONFIGURATION_KEY 1 |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 196 | |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 197 | typedef struct { |
| 198 | uint32_t iif; // The input interface index |
| 199 | struct in6_addr pfx96; // The source /96 nat64 prefix, bottom 32 bits must be 0 |
| 200 | struct in6_addr local6; // The full 128-bits of the destination IPv6 address |
| 201 | } ClatIngress6Key; |
| 202 | STRUCT_SIZE(ClatIngress6Key, 4 + 2 * 16); // 36 |
| 203 | |
| 204 | typedef struct { |
| 205 | uint32_t oif; // The output interface to redirect to (0 means don't redirect) |
| 206 | struct in_addr local4; // The destination IPv4 address |
| 207 | } ClatIngress6Value; |
| 208 | STRUCT_SIZE(ClatIngress6Value, 4 + 4); // 8 |
| 209 | |
Ken Chen | 335c0d4 | 2021-10-23 11:35:26 +0800 | [diff] [blame] | 210 | typedef struct { |
| 211 | uint32_t iif; // The input interface index |
| 212 | struct in_addr local4; // The source IPv4 address |
| 213 | } ClatEgress4Key; |
| 214 | STRUCT_SIZE(ClatEgress4Key, 4 + 4); // 8 |
| 215 | |
| 216 | typedef struct { |
| 217 | uint32_t oif; // The output interface to redirect to |
| 218 | struct in6_addr local6; // The full 128-bits of the source IPv6 address |
| 219 | struct in6_addr pfx96; // The destination /96 nat64 prefix, bottom 32 bits must be 0 |
| 220 | bool oifIsEthernet; // Whether the output interface requires ethernet header |
| 221 | uint8_t pad[3]; |
| 222 | } ClatEgress4Value; |
| 223 | STRUCT_SIZE(ClatEgress4Value, 4 + 2 * 16 + 1 + 3); // 40 |
| 224 | |
| 225 | #undef STRUCT_SIZE |