| 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> | 
|  | 23 | #include <netdutils/UidConstants.h> | 
|  | 24 |  | 
|  | 25 | // This header file is shared by eBPF kernel programs (C) and netd (C++) and | 
|  | 26 | // some of the maps are also accessed directly from Java mainline module code. | 
|  | 27 | // | 
|  | 28 | // Hence: explicitly pad all relevant structures and assert that their size | 
|  | 29 | // is the sum of the sizes of their fields. | 
|  | 30 | #define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.") | 
|  | 31 |  | 
|  | 32 | typedef struct { | 
|  | 33 | uint32_t uid; | 
|  | 34 | uint32_t tag; | 
|  | 35 | } UidTagValue; | 
|  | 36 | STRUCT_SIZE(UidTagValue, 2 * 4);  // 8 | 
|  | 37 |  | 
|  | 38 | typedef struct { | 
|  | 39 | uint32_t uid; | 
|  | 40 | uint32_t tag; | 
|  | 41 | uint32_t counterSet; | 
|  | 42 | uint32_t ifaceIndex; | 
|  | 43 | } StatsKey; | 
|  | 44 | STRUCT_SIZE(StatsKey, 4 * 4);  // 16 | 
|  | 45 |  | 
|  | 46 | typedef struct { | 
|  | 47 | uint64_t rxPackets; | 
|  | 48 | uint64_t rxBytes; | 
|  | 49 | uint64_t txPackets; | 
|  | 50 | uint64_t txBytes; | 
|  | 51 | } StatsValue; | 
|  | 52 | STRUCT_SIZE(StatsValue, 4 * 8);  // 32 | 
|  | 53 |  | 
|  | 54 | typedef struct { | 
|  | 55 | char name[IFNAMSIZ]; | 
|  | 56 | } IfaceValue; | 
|  | 57 | STRUCT_SIZE(IfaceValue, 16); | 
|  | 58 |  | 
|  | 59 | typedef struct { | 
|  | 60 | uint64_t rxBytes; | 
|  | 61 | uint64_t rxPackets; | 
|  | 62 | uint64_t txBytes; | 
|  | 63 | uint64_t txPackets; | 
|  | 64 | uint64_t tcpRxPackets; | 
|  | 65 | uint64_t tcpTxPackets; | 
|  | 66 | } Stats; | 
|  | 67 |  | 
|  | 68 | // Since we cannot garbage collect the stats map since device boot, we need to make these maps as | 
|  | 69 | // large as possible. The maximum size of number of map entries we can have is depend on the rlimit | 
|  | 70 | // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the | 
|  | 71 | // following fomula: | 
|  | 72 | //      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8) | 
|  | 73 | //      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries + | 
|  | 74 | //              elem_size * number_of_CPU | 
|  | 75 | // And the cost of each map currently used is(assume the device have 8 CPUs): | 
|  | 76 | // cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes | 
|  | 77 | // uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | 78 | // app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes | 
|  | 79 | // uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes | 
|  | 80 | // tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes | 
|  | 81 | // iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes | 
|  | 82 | // iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes | 
|  | 83 | // dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | 84 | // standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | 85 | // powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | 86 | // total:                                                                         4930Kbytes | 
|  | 87 | // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices | 
|  | 88 | // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module, | 
|  | 89 | // we don't have a total limit for data entries but only have limitation of tags each uid can have. | 
|  | 90 | // (default is 1024 in kernel); | 
|  | 91 |  | 
|  | 92 | // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation | 
|  | 93 | static const int COOKIE_UID_MAP_SIZE = 10000; | 
|  | 94 | static const int UID_COUNTERSET_MAP_SIZE = 2000; | 
|  | 95 | static const int APP_STATS_MAP_SIZE = 10000; | 
|  | 96 | static const int STATS_MAP_SIZE = 5000; | 
|  | 97 | static const int IFACE_INDEX_NAME_MAP_SIZE = 1000; | 
|  | 98 | static const int IFACE_STATS_MAP_SIZE = 1000; | 
|  | 99 | static const int CONFIGURATION_MAP_SIZE = 2; | 
|  | 100 | static const int UID_OWNER_MAP_SIZE = 2000; | 
|  | 101 |  | 
|  | 102 | #define BPF_PATH "/sys/fs/bpf/" | 
|  | 103 |  | 
|  | 104 | #define BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_egress_stats" | 
|  | 105 | #define BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_ingress_stats" | 
|  | 106 | #define XT_BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_ingress_xtbpf" | 
|  | 107 | #define XT_BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_egress_xtbpf" | 
|  | 108 | #define XT_BPF_ALLOWLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_allowlist_xtbpf" | 
|  | 109 | #define XT_BPF_DENYLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_denylist_xtbpf" | 
|  | 110 | #define CGROUP_SOCKET_PROG_PATH BPF_PATH "prog_netd_cgroupsock_inet_create" | 
|  | 111 |  | 
|  | 112 | #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account" | 
|  | 113 | #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME | 
|  | 114 |  | 
|  | 115 | #define COOKIE_TAG_MAP_PATH BPF_PATH "map_netd_cookie_tag_map" | 
|  | 116 | #define UID_COUNTERSET_MAP_PATH BPF_PATH "map_netd_uid_counterset_map" | 
|  | 117 | #define APP_UID_STATS_MAP_PATH BPF_PATH "map_netd_app_uid_stats_map" | 
|  | 118 | #define STATS_MAP_A_PATH BPF_PATH "map_netd_stats_map_A" | 
|  | 119 | #define STATS_MAP_B_PATH BPF_PATH "map_netd_stats_map_B" | 
|  | 120 | #define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "map_netd_iface_index_name_map" | 
|  | 121 | #define IFACE_STATS_MAP_PATH BPF_PATH "map_netd_iface_stats_map" | 
|  | 122 | #define CONFIGURATION_MAP_PATH BPF_PATH "map_netd_configuration_map" | 
|  | 123 | #define UID_OWNER_MAP_PATH BPF_PATH "map_netd_uid_owner_map" | 
|  | 124 | #define UID_PERMISSION_MAP_PATH BPF_PATH "map_netd_uid_permission_map" | 
|  | 125 |  | 
|  | 126 | enum UidOwnerMatchType { | 
|  | 127 | NO_MATCH = 0, | 
|  | 128 | HAPPY_BOX_MATCH = (1 << 0), | 
|  | 129 | PENALTY_BOX_MATCH = (1 << 1), | 
|  | 130 | DOZABLE_MATCH = (1 << 2), | 
|  | 131 | STANDBY_MATCH = (1 << 3), | 
|  | 132 | POWERSAVE_MATCH = (1 << 4), | 
|  | 133 | RESTRICTED_MATCH = (1 << 5), | 
|  | 134 | IIF_MATCH = (1 << 6), | 
|  | 135 | }; | 
|  | 136 |  | 
|  | 137 | enum BpfPermissionMatch { | 
|  | 138 | BPF_PERMISSION_INTERNET = 1 << 2, | 
|  | 139 | BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3, | 
|  | 140 | }; | 
|  | 141 | // In production we use two identical stats maps to record per uid stats and | 
|  | 142 | // do swap and clean based on the configuration specified here. The statsMapType | 
|  | 143 | // value in configuration map specified which map is currently in use. | 
|  | 144 | enum StatsMapType { | 
|  | 145 | SELECT_MAP_A, | 
|  | 146 | SELECT_MAP_B, | 
|  | 147 | }; | 
|  | 148 |  | 
|  | 149 | // TODO: change the configuration object from an 8-bit bitmask to an object with clearer | 
|  | 150 | // semantics, like a struct. | 
|  | 151 | typedef uint8_t BpfConfig; | 
|  | 152 | static const BpfConfig DEFAULT_CONFIG = 0; | 
|  | 153 |  | 
|  | 154 | typedef struct { | 
|  | 155 | // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above. | 
|  | 156 | uint32_t iif; | 
|  | 157 | // A bitmask of enum values in UidOwnerMatchType. | 
|  | 158 | uint32_t rule; | 
|  | 159 | } UidOwnerValue; | 
|  | 160 | STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8 | 
|  | 161 |  | 
|  | 162 | #define UID_RULES_CONFIGURATION_KEY 1 | 
|  | 163 | #define CURRENT_STATS_MAP_CONFIGURATION_KEY 2 | 
|  | 164 |  | 
|  | 165 | #define CLAT_INGRESS6_PROG_RAWIP_NAME "prog_clatd_schedcls_ingress6_clat_rawip" | 
|  | 166 | #define CLAT_INGRESS6_PROG_ETHER_NAME "prog_clatd_schedcls_ingress6_clat_ether" | 
|  | 167 |  | 
|  | 168 | #define CLAT_INGRESS6_PROG_RAWIP_PATH BPF_PATH CLAT_INGRESS6_PROG_RAWIP_NAME | 
|  | 169 | #define CLAT_INGRESS6_PROG_ETHER_PATH BPF_PATH CLAT_INGRESS6_PROG_ETHER_NAME | 
|  | 170 |  | 
|  | 171 | #define CLAT_INGRESS6_MAP_PATH BPF_PATH "map_clatd_clat_ingress6_map" | 
|  | 172 |  | 
|  | 173 | typedef struct { | 
|  | 174 | uint32_t iif;            // The input interface index | 
|  | 175 | struct in6_addr pfx96;   // The source /96 nat64 prefix, bottom 32 bits must be 0 | 
|  | 176 | struct in6_addr local6;  // The full 128-bits of the destination IPv6 address | 
|  | 177 | } ClatIngress6Key; | 
|  | 178 | STRUCT_SIZE(ClatIngress6Key, 4 + 2 * 16);  // 36 | 
|  | 179 |  | 
|  | 180 | typedef struct { | 
|  | 181 | uint32_t oif;           // The output interface to redirect to (0 means don't redirect) | 
|  | 182 | struct in_addr local4;  // The destination IPv4 address | 
|  | 183 | } ClatIngress6Value; | 
|  | 184 | STRUCT_SIZE(ClatIngress6Value, 4 + 4);  // 8 | 
|  | 185 |  | 
|  | 186 | #define CLAT_EGRESS4_PROG_RAWIP_NAME "prog_clatd_schedcls_egress4_clat_rawip" | 
|  | 187 | #define CLAT_EGRESS4_PROG_ETHER_NAME "prog_clatd_schedcls_egress4_clat_ether" | 
|  | 188 |  | 
|  | 189 | #define CLAT_EGRESS4_PROG_RAWIP_PATH BPF_PATH CLAT_EGRESS4_PROG_RAWIP_NAME | 
|  | 190 | #define CLAT_EGRESS4_PROG_ETHER_PATH BPF_PATH CLAT_EGRESS4_PROG_ETHER_NAME | 
|  | 191 |  | 
|  | 192 | #define CLAT_EGRESS4_MAP_PATH BPF_PATH "map_clatd_clat_egress4_map" | 
|  | 193 |  | 
|  | 194 | typedef struct { | 
|  | 195 | uint32_t iif;           // The input interface index | 
|  | 196 | struct in_addr local4;  // The source IPv4 address | 
|  | 197 | } ClatEgress4Key; | 
|  | 198 | STRUCT_SIZE(ClatEgress4Key, 4 + 4);  // 8 | 
|  | 199 |  | 
|  | 200 | typedef struct { | 
|  | 201 | uint32_t oif;            // The output interface to redirect to | 
|  | 202 | struct in6_addr local6;  // The full 128-bits of the source IPv6 address | 
|  | 203 | struct in6_addr pfx96;   // The destination /96 nat64 prefix, bottom 32 bits must be 0 | 
|  | 204 | bool oifIsEthernet;      // Whether the output interface requires ethernet header | 
|  | 205 | uint8_t pad[3]; | 
|  | 206 | } ClatEgress4Value; | 
|  | 207 | STRUCT_SIZE(ClatEgress4Value, 4 + 2 * 16 + 1 + 3);  // 40 | 
|  | 208 |  | 
|  | 209 | #undef STRUCT_SIZE |