|  | /* | 
|  | * Copyright (C) 2018 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <linux/if.h> | 
|  | #include <linux/if_ether.h> | 
|  | #include <linux/in.h> | 
|  | #include <linux/in6.h> | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | #include <string_view> | 
|  | #include "XtBpfProgLocations.h" | 
|  | #endif | 
|  |  | 
|  | // This header file is shared by eBPF kernel programs (C) and netd (C++) and | 
|  | // some of the maps are also accessed directly from Java mainline module code. | 
|  | // | 
|  | // Hence: explicitly pad all relevant structures and assert that their size | 
|  | // is the sum of the sizes of their fields. | 
|  | #define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.") | 
|  |  | 
|  | typedef struct { | 
|  | uint32_t uid; | 
|  | uint32_t tag; | 
|  | } UidTagValue; | 
|  | STRUCT_SIZE(UidTagValue, 2 * 4);  // 8 | 
|  |  | 
|  | typedef struct { | 
|  | uint32_t uid; | 
|  | uint32_t tag; | 
|  | uint32_t counterSet; | 
|  | uint32_t ifaceIndex; | 
|  | } StatsKey; | 
|  | STRUCT_SIZE(StatsKey, 4 * 4);  // 16 | 
|  |  | 
|  | typedef struct { | 
|  | uint64_t rxPackets; | 
|  | uint64_t rxBytes; | 
|  | uint64_t txPackets; | 
|  | uint64_t txBytes; | 
|  | } StatsValue; | 
|  | STRUCT_SIZE(StatsValue, 4 * 8);  // 32 | 
|  |  | 
|  | typedef struct { | 
|  | char name[IFNAMSIZ]; | 
|  | } IfaceValue; | 
|  | STRUCT_SIZE(IfaceValue, 16); | 
|  |  | 
|  | typedef struct { | 
|  | uint64_t rxBytes; | 
|  | uint64_t rxPackets; | 
|  | uint64_t txBytes; | 
|  | uint64_t txPackets; | 
|  | uint64_t tcpRxPackets; | 
|  | uint64_t tcpTxPackets; | 
|  | } Stats; | 
|  |  | 
|  | typedef struct { | 
|  | uint64_t timestampNs; | 
|  | uint32_t ifindex; | 
|  | uint32_t length; | 
|  |  | 
|  | uint32_t uid; | 
|  | uint32_t tag; | 
|  |  | 
|  | __be16 sport; | 
|  | __be16 dport; | 
|  |  | 
|  | bool egress; | 
|  | uint8_t ipProto; | 
|  | uint8_t tcpFlags; | 
|  | uint8_t ipVersion; // 4=IPv4, 6=IPv6, 0=unknown | 
|  | } PacketTrace; | 
|  | STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1); | 
|  |  | 
|  | // Since we cannot garbage collect the stats map since device boot, we need to make these maps as | 
|  | // large as possible. The maximum size of number of map entries we can have is depend on the rlimit | 
|  | // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the | 
|  | // following fomula: | 
|  | //      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8) | 
|  | //      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries + | 
|  | //              elem_size * number_of_CPU | 
|  | // And the cost of each map currently used is(assume the device have 8 CPUs): | 
|  | // cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes | 
|  | // uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | // app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes | 
|  | // uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes | 
|  | // tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes | 
|  | // iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes | 
|  | // iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes | 
|  | // dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | // standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | // powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes | 
|  | // packet_trace_ringbuf:key:  0 bytes, value: 24 bytes, cost:   32768 bytes    =    32Kbytes | 
|  | // total:                                                                         4962Kbytes | 
|  | // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices | 
|  | // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module, | 
|  | // we don't have a total limit for data entries but only have limitation of tags each uid can have. | 
|  | // (default is 1024 in kernel); | 
|  |  | 
|  | // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation | 
|  | static const int COOKIE_UID_MAP_SIZE = 10000; | 
|  | static const int UID_COUNTERSET_MAP_SIZE = 4000; | 
|  | static const int APP_STATS_MAP_SIZE = 10000; | 
|  | static const int STATS_MAP_SIZE = 5000; | 
|  | static const int IFACE_INDEX_NAME_MAP_SIZE = 1000; | 
|  | static const int IFACE_STATS_MAP_SIZE = 1000; | 
|  | static const int CONFIGURATION_MAP_SIZE = 2; | 
|  | static const int UID_OWNER_MAP_SIZE = 4000; | 
|  | static const int PACKET_TRACE_BUF_SIZE = 32 * 1024; | 
|  |  | 
|  | #ifdef __cplusplus | 
|  |  | 
|  | #define BPF_NETD_PATH "/sys/fs/bpf/netd_shared/" | 
|  |  | 
|  | #define BPF_EGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_egress_stats" | 
|  | #define BPF_INGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_ingress_stats" | 
|  |  | 
|  | #define ASSERT_STRING_EQUAL(s1, s2) \ | 
|  | static_assert(std::string_view(s1) == std::string_view(s2), "mismatch vs Android T netd") | 
|  |  | 
|  | /* -=-=-=-=- WARNING -=-=-=-=- | 
|  | * | 
|  | * These 4 xt_bpf program paths are actually defined by: | 
|  | *   //system/netd/include/mainline/XtBpfProgLocations.h | 
|  | * which is intentionally a non-automerged location. | 
|  | * | 
|  | * They are *UNCHANGEABLE* due to being hard coded in Android T's netd binary | 
|  | * as such we have compile time asserts that things match. | 
|  | * (which will be validated during build on mainline-prod branch against old system/netd) | 
|  | * | 
|  | * If you break this, netd on T will fail to start with your tethering mainline module. | 
|  | */ | 
|  | ASSERT_STRING_EQUAL(XT_BPF_INGRESS_PROG_PATH,   BPF_NETD_PATH "prog_netd_skfilter_ingress_xtbpf"); | 
|  | ASSERT_STRING_EQUAL(XT_BPF_EGRESS_PROG_PATH,    BPF_NETD_PATH "prog_netd_skfilter_egress_xtbpf"); | 
|  | ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf"); | 
|  | ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH,  BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf"); | 
|  |  | 
|  | #define CGROUP_SOCKET_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create" | 
|  |  | 
|  | #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account" | 
|  | #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME | 
|  |  | 
|  | #define COOKIE_TAG_MAP_PATH BPF_NETD_PATH "map_netd_cookie_tag_map" | 
|  | #define UID_COUNTERSET_MAP_PATH BPF_NETD_PATH "map_netd_uid_counterset_map" | 
|  | #define APP_UID_STATS_MAP_PATH BPF_NETD_PATH "map_netd_app_uid_stats_map" | 
|  | #define STATS_MAP_A_PATH BPF_NETD_PATH "map_netd_stats_map_A" | 
|  | #define STATS_MAP_B_PATH BPF_NETD_PATH "map_netd_stats_map_B" | 
|  | #define IFACE_INDEX_NAME_MAP_PATH BPF_NETD_PATH "map_netd_iface_index_name_map" | 
|  | #define IFACE_STATS_MAP_PATH BPF_NETD_PATH "map_netd_iface_stats_map" | 
|  | #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map" | 
|  | #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map" | 
|  | #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map" | 
|  | #define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf" | 
|  | #define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map" | 
|  |  | 
|  | #endif // __cplusplus | 
|  |  | 
|  | // LINT.IfChange(match_type) | 
|  | enum UidOwnerMatchType { | 
|  | NO_MATCH = 0, | 
|  | HAPPY_BOX_MATCH = (1 << 0), | 
|  | PENALTY_BOX_MATCH = (1 << 1), | 
|  | DOZABLE_MATCH = (1 << 2), | 
|  | STANDBY_MATCH = (1 << 3), | 
|  | POWERSAVE_MATCH = (1 << 4), | 
|  | RESTRICTED_MATCH = (1 << 5), | 
|  | LOW_POWER_STANDBY_MATCH = (1 << 6), | 
|  | IIF_MATCH = (1 << 7), | 
|  | LOCKDOWN_VPN_MATCH = (1 << 8), | 
|  | OEM_DENY_1_MATCH = (1 << 9), | 
|  | OEM_DENY_2_MATCH = (1 << 10), | 
|  | OEM_DENY_3_MATCH = (1 << 11), | 
|  | }; | 
|  | // LINT.ThenChange(packages/modules/Connectivity/service/src/com/android/server/BpfNetMaps.java) | 
|  |  | 
|  | enum BpfPermissionMatch { | 
|  | BPF_PERMISSION_INTERNET = 1 << 2, | 
|  | BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3, | 
|  | }; | 
|  | // In production we use two identical stats maps to record per uid stats and | 
|  | // do swap and clean based on the configuration specified here. The statsMapType | 
|  | // value in configuration map specified which map is currently in use. | 
|  | enum StatsMapType { | 
|  | SELECT_MAP_A, | 
|  | SELECT_MAP_B, | 
|  | }; | 
|  |  | 
|  | // TODO: change the configuration object from a bitmask to an object with clearer | 
|  | // semantics, like a struct. | 
|  | typedef uint32_t BpfConfig; | 
|  | static const BpfConfig DEFAULT_CONFIG = 0; | 
|  |  | 
|  | typedef struct { | 
|  | // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above. | 
|  | uint32_t iif; | 
|  | // A bitmask of enum values in UidOwnerMatchType. | 
|  | uint32_t rule; | 
|  | } UidOwnerValue; | 
|  | STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8 | 
|  |  | 
|  | // Entry in the configuration map that stores which UID rules are enabled. | 
|  | #define UID_RULES_CONFIGURATION_KEY 0 | 
|  | // Entry in the configuration map that stores which stats map is currently in use. | 
|  | #define CURRENT_STATS_MAP_CONFIGURATION_KEY 1 | 
|  |  | 
|  | #undef STRUCT_SIZE |