Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 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 | #include <linux/bpf.h> |
| 18 | #include <linux/if_ether.h> |
| 19 | #include <linux/in.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <string.h> |
Chenbo Feng | cc6cbb7 | 2018-05-08 13:45:08 -0700 | [diff] [blame] | 22 | #include <inttypes.h> |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 23 | #include <sys/socket.h> |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 24 | #include <sys/stat.h> |
Chenbo Feng | f43bf81 | 2017-12-15 18:27:22 -0800 | [diff] [blame] | 25 | #include <sys/utsname.h> |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 26 | #include <sstream> |
| 27 | #include <string> |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 28 | |
Chenbo Feng | cc6cbb7 | 2018-05-08 13:45:08 -0700 | [diff] [blame] | 29 | #include <android-base/properties.h> |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 30 | #include <android-base/stringprintf.h> |
| 31 | #include <android-base/unique_fd.h> |
| 32 | #include <netdutils/Slice.h> |
| 33 | #include <netdutils/StatusOr.h> |
| 34 | #include "bpf/BpfUtils.h" |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 35 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 36 | using android::base::StringPrintf; |
| 37 | using android::base::unique_fd; |
Chenbo Feng | cc6cbb7 | 2018-05-08 13:45:08 -0700 | [diff] [blame] | 38 | using android::base::GetUintProperty; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 39 | using android::netdutils::Slice; |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 40 | using android::netdutils::statusFromErrno; |
| 41 | using android::netdutils::StatusOr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 42 | |
Chenbo Feng | 2c67f26 | 2018-04-26 10:37:55 -0700 | [diff] [blame] | 43 | #define ptr_to_u64(x) ((uint64_t)(uintptr_t)x) |
| 44 | #define DEFAULT_LOG_LEVEL 1 |
| 45 | |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 46 | namespace android { |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 47 | namespace bpf { |
| 48 | |
Chenbo Feng | 2950321 | 2018-04-24 11:50:02 -0700 | [diff] [blame] | 49 | /* The bpf_attr is a union which might have a much larger size then the struct we are using, while |
| 50 | * The inline initializer only reset the field we are using and leave the reset of the memory as |
| 51 | * is. The bpf kernel code will performs a much stricter check to ensure all unused field is 0. So |
| 52 | * this syscall will normally fail with E2BIG if we don't do a memset to bpf_attr. |
| 53 | */ |
Chenbo Feng | 2c67f26 | 2018-04-26 10:37:55 -0700 | [diff] [blame] | 54 | bool operator==(const StatsKey& lhs, const StatsKey& rhs) { |
| 55 | return ((lhs.uid == rhs.uid) && (lhs.tag == rhs.tag) && (lhs.counterSet == rhs.counterSet) && |
| 56 | (lhs.ifaceIndex == rhs.ifaceIndex)); |
| 57 | } |
| 58 | |
| 59 | bool operator==(const UidTag& lhs, const UidTag& rhs) { |
| 60 | return ((lhs.uid == rhs.uid) && (lhs.tag == rhs.tag)); |
| 61 | } |
| 62 | |
| 63 | bool operator==(const StatsValue& lhs, const StatsValue& rhs) { |
| 64 | return ((lhs.rxBytes == rhs.rxBytes) && (lhs.txBytes == rhs.txBytes) && |
| 65 | (lhs.rxPackets == rhs.rxPackets) && (lhs.txPackets == rhs.txPackets)); |
| 66 | } |
| 67 | |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 68 | int bpf(int cmd, Slice bpfAttr) { |
| 69 | return syscall(__NR_bpf, cmd, bpfAttr.base(), bpfAttr.size()); |
| 70 | } |
| 71 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 72 | int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, |
| 73 | uint32_t map_flags) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 74 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 75 | memset(&attr, 0, sizeof(attr)); |
| 76 | attr.map_type = map_type; |
| 77 | attr.key_size = key_size; |
| 78 | attr.value_size = value_size; |
| 79 | attr.max_entries = max_entries; |
| 80 | attr.map_flags = map_flags; |
| 81 | |
| 82 | return bpf(BPF_MAP_CREATE, Slice(&attr, sizeof(attr))); |
| 83 | } |
| 84 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 85 | int writeToMapEntry(const base::unique_fd& map_fd, void* key, void* value, uint64_t flags) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 86 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 87 | memset(&attr, 0, sizeof(attr)); |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 88 | attr.map_fd = map_fd.get(); |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 89 | attr.key = ptr_to_u64(key); |
| 90 | attr.value = ptr_to_u64(value); |
| 91 | attr.flags = flags; |
| 92 | |
| 93 | return bpf(BPF_MAP_UPDATE_ELEM, Slice(&attr, sizeof(attr))); |
| 94 | } |
| 95 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 96 | int findMapEntry(const base::unique_fd& map_fd, void* key, void* value) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 97 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 98 | memset(&attr, 0, sizeof(attr)); |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 99 | attr.map_fd = map_fd.get(); |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 100 | attr.key = ptr_to_u64(key); |
| 101 | attr.value = ptr_to_u64(value); |
| 102 | |
| 103 | return bpf(BPF_MAP_LOOKUP_ELEM, Slice(&attr, sizeof(attr))); |
| 104 | } |
| 105 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 106 | int deleteMapEntry(const base::unique_fd& map_fd, void* key) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 107 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 108 | memset(&attr, 0, sizeof(attr)); |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 109 | attr.map_fd = map_fd.get(); |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 110 | attr.key = ptr_to_u64(key); |
| 111 | |
| 112 | return bpf(BPF_MAP_DELETE_ELEM, Slice(&attr, sizeof(attr))); |
| 113 | } |
| 114 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 115 | int getNextMapKey(const base::unique_fd& map_fd, void* key, void* next_key) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 116 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 117 | memset(&attr, 0, sizeof(attr)); |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 118 | attr.map_fd = map_fd.get(); |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 119 | attr.key = ptr_to_u64(key); |
| 120 | attr.next_key = ptr_to_u64(next_key); |
| 121 | |
| 122 | return bpf(BPF_MAP_GET_NEXT_KEY, Slice(&attr, sizeof(attr))); |
| 123 | } |
| 124 | |
Chenbo Feng | 2950321 | 2018-04-24 11:50:02 -0700 | [diff] [blame] | 125 | int getFirstMapKey(const base::unique_fd& map_fd, void* firstKey) { |
| 126 | bpf_attr attr; |
| 127 | memset(&attr, 0, sizeof(attr)); |
| 128 | attr.map_fd = map_fd.get(); |
| 129 | attr.key = 0; |
| 130 | attr.next_key = ptr_to_u64(firstKey); |
| 131 | |
| 132 | return bpf(BPF_MAP_GET_NEXT_KEY, Slice(&attr, sizeof(attr))); |
| 133 | } |
| 134 | |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 135 | int bpfProgLoad(bpf_prog_type prog_type, Slice bpf_insns, const char* license, |
| 136 | uint32_t kern_version, Slice bpf_log) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 137 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 138 | memset(&attr, 0, sizeof(attr)); |
| 139 | attr.prog_type = prog_type; |
| 140 | attr.insns = ptr_to_u64(bpf_insns.base()); |
| 141 | attr.insn_cnt = bpf_insns.size() / sizeof(struct bpf_insn); |
| 142 | attr.license = ptr_to_u64((void*)license); |
| 143 | attr.log_buf = ptr_to_u64(bpf_log.base()); |
| 144 | attr.log_size = bpf_log.size(); |
| 145 | attr.log_level = DEFAULT_LOG_LEVEL; |
| 146 | attr.kern_version = kern_version; |
| 147 | int ret = bpf(BPF_PROG_LOAD, Slice(&attr, sizeof(attr))); |
| 148 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 149 | if (ret < 0) { |
| 150 | std::string prog_log = netdutils::toString(bpf_log); |
| 151 | std::istringstream iss(prog_log); |
| 152 | for (std::string line; std::getline(iss, line);) { |
| 153 | ALOGE("%s", line.c_str()); |
| 154 | } |
| 155 | } |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 156 | return ret; |
| 157 | } |
| 158 | |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 159 | int mapPin(const base::unique_fd& map_fd, const char* pathname) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 160 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 161 | memset(&attr, 0, sizeof(attr)); |
| 162 | attr.pathname = ptr_to_u64((void*)pathname); |
Chenbo Feng | c10a8a4 | 2017-12-15 13:56:33 -0800 | [diff] [blame] | 163 | attr.bpf_fd = map_fd.get(); |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 164 | |
| 165 | return bpf(BPF_OBJ_PIN, Slice(&attr, sizeof(attr))); |
| 166 | } |
| 167 | |
Chenbo Feng | be33bd5 | 2017-11-27 18:21:54 -0800 | [diff] [blame] | 168 | int mapRetrieve(const char* pathname, uint32_t flag) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 169 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 170 | memset(&attr, 0, sizeof(attr)); |
| 171 | attr.pathname = ptr_to_u64((void*)pathname); |
Chenbo Feng | be33bd5 | 2017-11-27 18:21:54 -0800 | [diff] [blame] | 172 | attr.file_flags = flag; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 173 | return bpf(BPF_OBJ_GET, Slice(&attr, sizeof(attr))); |
| 174 | } |
| 175 | |
| 176 | int attachProgram(bpf_attach_type type, uint32_t prog_fd, uint32_t cg_fd) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 177 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 178 | memset(&attr, 0, sizeof(attr)); |
| 179 | attr.target_fd = cg_fd; |
| 180 | attr.attach_bpf_fd = prog_fd; |
| 181 | attr.attach_type = type; |
| 182 | |
| 183 | return bpf(BPF_PROG_ATTACH, Slice(&attr, sizeof(attr))); |
| 184 | } |
| 185 | |
| 186 | int detachProgram(bpf_attach_type type, uint32_t cg_fd) { |
Christopher Ferris | aa31c62 | 2018-01-31 17:20:25 -0800 | [diff] [blame] | 187 | bpf_attr attr; |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 188 | memset(&attr, 0, sizeof(attr)); |
| 189 | attr.target_fd = cg_fd; |
| 190 | attr.attach_type = type; |
| 191 | |
| 192 | return bpf(BPF_PROG_DETACH, Slice(&attr, sizeof(attr))); |
| 193 | } |
| 194 | |
Chenbo Feng | ed37fea | 2017-12-13 19:35:01 -0800 | [diff] [blame] | 195 | uint64_t getSocketCookie(int sockFd) { |
| 196 | uint64_t sock_cookie; |
| 197 | socklen_t cookie_len = sizeof(sock_cookie); |
| 198 | int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len); |
| 199 | if (res < 0) { |
| 200 | res = -errno; |
| 201 | ALOGE("Failed to get socket cookie: %s\n", strerror(errno)); |
| 202 | errno = -res; |
Chenbo Feng | 0cef0cd | 2018-04-13 19:50:49 -0700 | [diff] [blame] | 203 | // 0 is an invalid cookie. See sock_gen_cookie. |
| 204 | return NONEXISTENT_COOKIE; |
Chenbo Feng | ed37fea | 2017-12-13 19:35:01 -0800 | [diff] [blame] | 205 | } |
| 206 | return sock_cookie; |
| 207 | } |
| 208 | |
Chenbo Feng | f43bf81 | 2017-12-15 18:27:22 -0800 | [diff] [blame] | 209 | bool hasBpfSupport() { |
| 210 | struct utsname buf; |
| 211 | int kernel_version_major; |
| 212 | int kernel_version_minor; |
| 213 | |
Chenbo Feng | cc6cbb7 | 2018-05-08 13:45:08 -0700 | [diff] [blame] | 214 | uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0); |
| 215 | if (api_level == 0) { |
| 216 | ALOGE("Cannot determine initial API level of the device"); |
| 217 | api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0); |
| 218 | } |
| 219 | |
Chenbo Feng | f43bf81 | 2017-12-15 18:27:22 -0800 | [diff] [blame] | 220 | int ret = uname(&buf); |
| 221 | if (ret) { |
| 222 | return false; |
| 223 | } |
| 224 | char dummy; |
| 225 | ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy); |
Chenbo Feng | cc6cbb7 | 2018-05-08 13:45:08 -0700 | [diff] [blame] | 226 | if (ret >= 2 && ((kernel_version_major > 4) || |
| 227 | (kernel_version_major == 4 && kernel_version_minor >= 9))) { |
| 228 | // Check if the device is shipped originally with android P. |
| 229 | return api_level >= MINIMUM_API_REQUIRED; |
| 230 | } |
| 231 | return false; |
Chenbo Feng | f43bf81 | 2017-12-15 18:27:22 -0800 | [diff] [blame] | 232 | } |
| 233 | |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 234 | } // namespace bpf |
Chenbo Feng | f275968 | 2017-10-10 17:31:57 -0700 | [diff] [blame] | 235 | } // namespace android |