Home | History | Annotate | Download | only in bpf
      1 /*
      2  * Copyright (C) 2017 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 #ifndef BPF_BPFUTILS_H
     18 #define BPF_BPFUTILS_H
     19 
     20 #include <linux/bpf.h>
     21 #include <linux/if_ether.h>
     22 #include <linux/in.h>
     23 #include <linux/unistd.h>
     24 #include <net/if.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <sys/socket.h>
     28 
     29 #include "android-base/unique_fd.h"
     30 #include "netdutils/Slice.h"
     31 #include "netdutils/StatusOr.h"
     32 
     33 #define BPF_PASS 1
     34 #define BPF_DROP 0
     35 
     36 namespace android {
     37 namespace bpf {
     38 
     39 struct UidTag {
     40     uint32_t uid;
     41     uint32_t tag;
     42 };
     43 
     44 struct StatsKey {
     45     uint32_t uid;
     46     uint32_t tag;
     47     uint32_t counterSet;
     48     uint32_t ifaceIndex;
     49 };
     50 
     51 struct StatsValue {
     52     uint64_t rxPackets;
     53     uint64_t rxBytes;
     54     uint64_t txPackets;
     55     uint64_t txBytes;
     56 };
     57 
     58 struct Stats {
     59     uint64_t rxBytes;
     60     uint64_t rxPackets;
     61     uint64_t txBytes;
     62     uint64_t txPackets;
     63     uint64_t tcpRxPackets;
     64     uint64_t tcpTxPackets;
     65 };
     66 
     67 struct IfaceValue {
     68     char name[IFNAMSIZ];
     69 };
     70 
     71 #ifndef DEFAULT_OVERFLOWUID
     72 #define DEFAULT_OVERFLOWUID 65534
     73 #endif
     74 
     75 #define BPF_PATH "/sys/fs/bpf"
     76 
     77 // Since we cannot garbage collect the stats map since device boot, we need to make these maps as
     78 // large as possible. The maximum size of number of map entries we can have is depend on the rlimit
     79 // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the
     80 // following fomula:
     81 //      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8)
     82 //      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries +
     83 //              elem_size * number_of_CPU
     84 // And the cost of each map currently used is(assume the device have 8 CPUs):
     85 // cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes
     86 // uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
     87 // app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes
     88 // uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
     89 // tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
     90 // iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes
     91 // iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes
     92 // dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
     93 // standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
     94 // powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
     95 // total:                                                                         4930Kbytes
     96 // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices
     97 // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module,
     98 // we don't have a total limit for data entries but only have limitation of tags each uid can have.
     99 // (default is 1024 in kernel);
    100 
    101 constexpr const int COOKIE_UID_MAP_SIZE = 10000;
    102 constexpr const int UID_COUNTERSET_MAP_SIZE = 2000;
    103 constexpr const int UID_STATS_MAP_SIZE = 10000;
    104 constexpr const int TAG_STATS_MAP_SIZE = 10000;
    105 constexpr const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
    106 constexpr const int IFACE_STATS_MAP_SIZE = 1000;
    107 constexpr const int UID_OWNER_MAP_SIZE = 2000;
    108 
    109 constexpr const char* BPF_EGRESS_PROG_PATH = BPF_PATH "/egress_prog";
    110 constexpr const char* BPF_INGRESS_PROG_PATH = BPF_PATH "/ingress_prog";
    111 constexpr const char* XT_BPF_INGRESS_PROG_PATH = BPF_PATH "/xt_bpf_ingress_prog";
    112 constexpr const char* XT_BPF_EGRESS_PROG_PATH = BPF_PATH "/xt_bpf_egress_prog";
    113 
    114 constexpr const char* CGROUP_ROOT_PATH = "/dev/cg2_bpf";
    115 
    116 constexpr const char* COOKIE_TAG_MAP_PATH = BPF_PATH "/traffic_cookie_tag_map";
    117 constexpr const char* UID_COUNTERSET_MAP_PATH = BPF_PATH "/traffic_uid_counterSet_map";
    118 constexpr const char* APP_UID_STATS_MAP_PATH = BPF_PATH "/traffic_app_uid_stats_map";
    119 constexpr const char* UID_STATS_MAP_PATH = BPF_PATH "/traffic_uid_stats_map";
    120 constexpr const char* TAG_STATS_MAP_PATH = BPF_PATH "/traffic_tag_stats_map";
    121 constexpr const char* IFACE_INDEX_NAME_MAP_PATH = BPF_PATH "/traffic_iface_index_name_map";
    122 constexpr const char* IFACE_STATS_MAP_PATH = BPF_PATH "/traffic_iface_stats_map";
    123 constexpr const char* DOZABLE_UID_MAP_PATH = BPF_PATH "/traffic_dozable_uid_map";
    124 constexpr const char* STANDBY_UID_MAP_PATH = BPF_PATH "/traffic_standby_uid_map";
    125 constexpr const char* POWERSAVE_UID_MAP_PATH = BPF_PATH "/traffic_powersave_uid_map";
    126 
    127 constexpr const int OVERFLOW_COUNTERSET = 2;
    128 
    129 constexpr const uint64_t NONEXISTENT_COOKIE = 0;
    130 
    131 constexpr const int MINIMUM_API_REQUIRED = 28;
    132 
    133 int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
    134               uint32_t max_entries, uint32_t map_flags);
    135 int writeToMapEntry(const base::unique_fd& map_fd, void* key, void* value, uint64_t flags);
    136 int findMapEntry(const base::unique_fd& map_fd, void* key, void* value);
    137 int deleteMapEntry(const base::unique_fd& map_fd, void* key);
    138 int getNextMapKey(const base::unique_fd& map_fd, void* key, void* next_key);
    139 int getFirstMapKey(const base::unique_fd& map_fd, void* firstKey);
    140 int bpfProgLoad(bpf_prog_type prog_type, netdutils::Slice bpf_insns, const char* license,
    141                 uint32_t kern_version, netdutils::Slice bpf_log);
    142 int mapPin(const base::unique_fd& map_fd, const char* pathname);
    143 int mapRetrieve(const char* pathname, uint32_t flags);
    144 int attachProgram(bpf_attach_type type, uint32_t prog_fd, uint32_t cg_fd);
    145 int detachProgram(bpf_attach_type type, uint32_t cg_fd);
    146 uint64_t getSocketCookie(int sockFd);
    147 bool hasBpfSupport();
    148 
    149 #define SKIP_IF_BPF_NOT_SUPPORTED     \
    150     do {                              \
    151         if (!hasBpfSupport()) return; \
    152     } while (0)
    153 
    154 constexpr int BPF_CONTINUE = 0;
    155 constexpr int BPF_DELETED = 1;
    156 
    157 bool operator==(const StatsValue& lhs, const StatsValue& rhs);
    158 bool operator==(const UidTag& lhs, const UidTag& rhs);
    159 bool operator==(const StatsKey& lhs, const StatsKey& rhs);
    160 }  // namespace bpf
    161 }  // namespace android
    162 
    163 #endif
    164