blob: 10d0cf4725aa50dfc532373ff81a996580dad1ea [file] [log] [blame]
Chenbo Fengf2759682017-10-10 17:31:57 -07001/*
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
Chenbo Fengc10a8a42017-12-15 13:56:33 -080017#define LOG_TAG "TrafficController"
Chenbo Feng33cc1032017-10-23 15:16:37 -070018#include <inttypes.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070019#include <linux/bpf.h>
20#include <linux/if_ether.h>
21#include <linux/in.h>
22#include <linux/inet_diag.h>
Chenbo Feng116d0552017-12-04 17:25:19 -080023#include <linux/netlink.h>
24#include <linux/sock_diag.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070025#include <linux/unistd.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080026#include <net/if.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070027#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080030#include <sys/stat.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080031#include <sys/types.h>
Chenbo Feng33cc1032017-10-23 15:16:37 -070032#include <sys/utsname.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080033#include <sys/wait.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080034#include <unordered_set>
35#include <vector>
36
37#include <android-base/stringprintf.h>
38#include <android-base/unique_fd.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080039#include <logwrap/logwrap.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080040#include <netdutils/StatusOr.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070041
Chenbo Feng116d0552017-12-04 17:25:19 -080042#include <netdutils/Misc.h>
43#include <netdutils/Syscalls.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070044#include "TrafficController.h"
Chenbo Fengc10a8a42017-12-15 13:56:33 -080045#include "bpf/BpfUtils.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080046
Chenbo Feng7e974052018-02-28 22:57:21 -080047#include "InterfaceController.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080048#include "NetlinkListener.h"
Chenbo Feng33cc1032017-10-23 15:16:37 -070049#include "qtaguid/qtaguid.h"
Chenbo Fengf2759682017-10-10 17:31:57 -070050
Chenbo Fengc10a8a42017-12-15 13:56:33 -080051using namespace android::bpf;
Chenbo Fengf2759682017-10-10 17:31:57 -070052
53namespace android {
54namespace net {
55
Chenbo Fengc10a8a42017-12-15 13:56:33 -080056using base::StringPrintf;
57using base::unique_fd;
Chenbo Feng116d0552017-12-04 17:25:19 -080058using netdutils::extract;
59using netdutils::Slice;
60using netdutils::sSyscalls;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080061using netdutils::Status;
62using netdutils::statusFromErrno;
63using netdutils::StatusOr;
Chenbo Feng116d0552017-12-04 17:25:19 -080064using netdutils::status::ok;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080065
Chenbo Feng116d0552017-12-04 17:25:19 -080066constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
67constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
68
69StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener() {
70 const auto& sys = sSyscalls.get();
71 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
72 const int domain = AF_NETLINK;
73 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
74 const int protocol = NETLINK_INET_DIAG;
75 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
76
77 sockaddr_nl addr = {
78 .nl_family = AF_NETLINK,
79 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
80 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
81 RETURN_IF_NOT_OK(sys.bind(sock, addr));
82
83 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
84 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
85
86 std::unique_ptr<NetlinkListenerInterface> listener =
87 std::make_unique<NetlinkListener>(std::move(event), std::move(sock));
88
89 return listener;
90}
91
Chenbo Fengc10a8a42017-12-15 13:56:33 -080092Status TrafficController::start() {
Chenbo Fengf43bf812017-12-15 18:27:22 -080093 ebpfSupported = hasBpfSupport();
94 if (!ebpfSupported) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -080095 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -070096 }
97
98 /* When netd restart from a crash without total system reboot, the program
99 * is still attached to the cgroup, detach it so the program can be freed
100 * and we can load and attach new program into the target cgroup.
101 *
102 * TODO: Scrape existing socket when run-time restart and clean up the map
103 * if the socket no longer exist
104 */
105
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800106 ALOGI("START to load TrafficController");
Chenbo Fengf2759682017-10-10 17:31:57 -0700107
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800108 ASSIGN_OR_RETURN(mCookieTagMap,
109 setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
110 COOKIE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
Chenbo Fengf2759682017-10-10 17:31:57 -0700111
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800112 // Allow both netd and system server to obtain map fd from the path. Chown the group to
113 // net_bw_acct does not grant all process in that group the permission to access bpf maps. They
114 // still need correct sepolicy to read/write the map. And only system_server and netd have that
115 // permission for now.
Chenbo Fengf43bf812017-12-15 18:27:22 -0800116 int ret = chown(COOKIE_UID_MAP_PATH, AID_ROOT, AID_NET_BW_ACCT);
Chenbo Fengf2759682017-10-10 17:31:57 -0700117 if (ret) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800118 return statusFromErrno(errno, "change cookieTagMap group failed.");
119 }
120 ret = chmod(COOKIE_UID_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
121 if (ret) {
122 return statusFromErrno(errno, "change cookieTagMap mode failed.");
Chenbo Fengf2759682017-10-10 17:31:57 -0700123 }
124
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800125 ASSIGN_OR_RETURN(mUidCounterSetMap,
126 setUpBPFMap(sizeof(uint32_t), sizeof(uint32_t), UID_COUNTERSET_MAP_SIZE,
127 UID_COUNTERSET_MAP_PATH, BPF_MAP_TYPE_HASH));
128 // Only netd can access the file.
129 ret = chmod(UID_COUNTERSET_MAP_PATH, S_IRWXU);
Chenbo Fengf2759682017-10-10 17:31:57 -0700130 if (ret) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800131 return statusFromErrno(errno, "change uidCounterSetMap mode failed.");
Chenbo Fengf2759682017-10-10 17:31:57 -0700132 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800133
134 ASSIGN_OR_RETURN(mUidStatsMap,
Chenbo Fengf43bf812017-12-15 18:27:22 -0800135 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
136 UID_STATS_MAP_SIZE, UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800137 // Change the file mode of pinned map so both netd and system server can get the map fd
138 // from it.
139 ret = chown(UID_STATS_MAP_PATH, AID_ROOT, AID_NET_BW_ACCT);
140 if (ret) {
141 return statusFromErrno(errno, "change uidStatsMap group failed.");
142 }
143 ret = chmod(UID_STATS_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
144 if (ret) {
145 return statusFromErrno(errno, "change uidStatsMap mode failed.");
146 }
147
148 ASSIGN_OR_RETURN(mTagStatsMap,
Chenbo Fengf43bf812017-12-15 18:27:22 -0800149 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
150 TAG_STATS_MAP_SIZE, TAG_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800151 // Change the file mode of pinned map so both netd and system server can get the map fd
152 // from the path.
153 ret = chown(TAG_STATS_MAP_PATH, AID_ROOT, AID_NET_BW_STATS);
154 if (ret) {
155 return statusFromErrno(errno, "change tagStatsMap group failed.");
156 }
157 ret = chmod(TAG_STATS_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
158 if (ret) {
159 return statusFromErrno(errno, "change tagStatsMap mode failed.");
160 }
161
Chenbo Feng7e974052018-02-28 22:57:21 -0800162 ASSIGN_OR_RETURN(mIfaceIndexNameMap,
163 setUpBPFMap(sizeof(uint32_t), IFNAMSIZ, IFACE_INDEX_NAME_MAP_SIZE,
164 IFACE_INDEX_NAME_MAP_PATH, BPF_MAP_TYPE_HASH));
165 // Change the file mode of pinned map so both netd and system server can get the map fd
166 // from the path.
167 ret = chown(IFACE_INDEX_NAME_MAP_PATH, AID_ROOT, AID_NET_BW_STATS);
168 if (ret) {
169 return statusFromErrno(errno, "change ifaceIndexNameMap group failed.");
170 }
171 ret = chmod(IFACE_INDEX_NAME_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
172 if (ret) {
173 return statusFromErrno(errno, "change ifaceIndexNameMap mode failed.");
174 }
175
176 // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
177 // already running, so it will call addInterface() when any new interface appears.
178 std::map<std::string, uint32_t> ifacePairs;
179 ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
180 for (const auto& ifacePair:ifacePairs) {
181 addInterface(ifacePair.first.c_str(), ifacePair.second);
182 }
183
Chenbo Feng116d0552017-12-04 17:25:19 -0800184 auto result = makeSkDestroyListener();
185 if (!isOk(result)) {
186 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
187 } else {
188 mSkDestroyListener = std::move(result.value());
189 }
190 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
191 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
192 inet_diag_msg diagmsg = {};
193 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
194 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
195 return;
196 }
197 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
198 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
199
200 deleteMapEntry(mCookieTagMap, &sock_cookie);
201 };
202 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
203
204 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
205 // properly.
206 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
207 // Ignore NLMSG_DONE messages
208 inet_diag_msg diagmsg = {};
209 extract(msg, diagmsg);
210 };
211 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
212
Chenbo Feng05393d82018-01-09 15:18:43 -0800213 int* status = nullptr;
214
215 std::vector<const char*> prog_args{
216 "/system/bin/bpfloader",
217 };
218 ret = access(BPF_INGRESS_PROG_PATH, R_OK);
219 if (ret != 0 && errno == ENOENT) {
220 prog_args.push_back((char*)"-i");
221 }
222 ret = access(BPF_EGRESS_PROG_PATH, R_OK);
223 if (ret != 0 && errno == ENOENT) {
224 prog_args.push_back((char*)"-e");
225 }
226
227 if (prog_args.size() == 1) {
228 // both program are loaded already.
229 return netdutils::status::ok;
230 }
231
232 prog_args.push_back(nullptr);
233 ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
234 if (ret) {
235 ret = errno;
236 ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
237 return statusFromErrno(ret, "run bpf loader failed");
238 }
239 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700240}
241
Chenbo Fengf2759682017-10-10 17:31:57 -0700242int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800243 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
244 if (!ebpfSupported) return 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700245
Chenbo Fengf2759682017-10-10 17:31:57 -0700246 uint64_t sock_cookie = getSocketCookie(sockFd);
247 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
248 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
249
250 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
251 // flag so it will insert a new entry to the map if that value doesn't exist
252 // yet. And update the tag if there is already a tag stored. Since the eBPF
253 // program in kernel only read this map, and is protected by rcu read lock. It
254 // should be fine to cocurrently update the map while eBPF program is running.
255 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
256 if (res < 0) {
257 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800258 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700259 }
260
261 return res;
262}
263
264int TrafficController::untagSocket(int sockFd) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800265 if (legacy_untagSocket(sockFd)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700266 if (!ebpfSupported) return 0;
Chenbo Fengf2759682017-10-10 17:31:57 -0700267 uint64_t sock_cookie = getSocketCookie(sockFd);
268
269 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
270 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
271 if (res) {
272 res = -errno;
273 ALOGE("Failed to untag socket: %s\n", strerror(errno));
274 }
275 return res;
276}
277
278int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
279 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700280 int res;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800281 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
282 if (!ebpfSupported) return 0;
283
284 // The default counter set for all uid is 0, so deleting the current counterset for that uid
285 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700286 if (counterSetNum == 0) {
287 res = deleteMapEntry(mUidCounterSetMap, &uid);
288 if (res == 0 || (res == -1 && errno == ENOENT)) {
289 return 0;
290 } else {
291 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
292 return -errno;
293 }
294 }
295
296 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
297 if (res < 0) {
298 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800299 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700300 }
301 return res;
302}
303
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800304// TODO: Add a lock for delete tag Data so when several request for different uid comes in, they do
305// not race with each other.
Chenbo Fengf2759682017-10-10 17:31:57 -0700306int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
307 int res = 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700308
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800309 if (legacy_deleteTagData(tag, uid)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700310 if (!ebpfSupported) return 0;
311
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800312 uint64_t curCookie = NONEXIST_COOKIE;
Chenbo Fengf2759682017-10-10 17:31:57 -0700313 uint64_t nextCookie = 0;
314 UidTag tmp_uidtag;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800315 std::vector<uint64_t> cookieList;
316 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
317 // the tags related to the uid if the tag is 0, we start the map iteration with a cookie of
318 // INET_DIAG_NOCOOKIE because it's guaranteed that that will not be in the map.
319 while (getNextMapKey(mCookieTagMap, &curCookie, &nextCookie) != -1) {
320 res = findMapEntry(mCookieTagMap, &nextCookie, &tmp_uidtag);
Chenbo Fengf2759682017-10-10 17:31:57 -0700321 if (res < 0) {
322 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800323 ALOGE("Failed to get tag info(cookie = %" PRIu64 ": %s\n", nextCookie, strerror(errno));
324 // Continue to look for next entry.
325 curCookie = nextCookie;
326 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700327 }
328
329 if (tmp_uidtag.uid == uid && (tmp_uidtag.tag == tag || tag == 0)) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800330 res = deleteMapEntry(mCookieTagMap, &nextCookie);
331 if (res < 0 && errno != ENOENT) {
Chenbo Fengf2759682017-10-10 17:31:57 -0700332 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800333 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", nextCookie,
334 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700335 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800336 } else {
337 // Move forward to next cookie in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700338 curCookie = nextCookie;
339 }
340 }
341
342 // Now we go through the Tag stats map and delete the data entry with correct uid and tag
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800343 // combination. Or all tag stats under that uid if the target tag is 0. The initial key is
344 // set to the nonexist_statskey because it will never be in the map, and thus getNextMapKey will
345 // return 0 and set nextKey to the first key in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700346 struct StatsKey curKey, nextKey;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800347 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800348 while (getNextMapKey(mTagStatsMap, &curKey, &nextKey) != -1) {
349 if (nextKey.uid == uid && (nextKey.tag == tag || tag == 0)) {
350 res = deleteMapEntry(mTagStatsMap, &nextKey);
351 if (res < 0 && errno != ENOENT) {
352 // Skip the current entry if unexpected error happened.
353 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
354 strerror(errno));
355 curKey = nextKey;
Chenbo Fengf2759682017-10-10 17:31:57 -0700356 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800357 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700358 curKey = nextKey;
359 }
360 }
361
362 // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
Chenbo Fenged37fea2017-12-13 19:35:01 -0800363 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800364 if (tag != 0) return 0;
365
366 res = deleteMapEntry(mUidCounterSetMap, &uid);
367 if (res < 0 && errno != ENOENT) {
368 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
369 }
370
371 // For the uid stats deleted from the map, move them into a special
372 // removed uid entry. The removed uid is stored in uid 0, tag 0 and
373 // counterSet as COUNTERSETS_LIMIT.
374 StatsKey removedStatsKey = {0, 0, COUNTERSETS_LIMIT, 0};
Chenbo Fengf43bf812017-12-15 18:27:22 -0800375 StatsValue removedStatsTotal = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800376 res = findMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal);
377 if (res < 0 && errno != ENOENT) {
378 ALOGE("Failed to get stats of removed uid: %s", strerror(errno));
379 }
380
Chenbo Fengf43bf812017-12-15 18:27:22 -0800381 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800382 while (getNextMapKey(mUidStatsMap, &curKey, &nextKey) != -1) {
383 if (nextKey.uid == uid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800384 StatsValue old_stats = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800385 res = findMapEntry(mUidStatsMap, &nextKey, &old_stats);
386 if (res < 0) {
387 if (errno != ENOENT) {
388 // if errno is ENOENT Somebody else deleted nextKey. Lookup the next key from
389 // curKey. If we have other error. Skip this key to avoid an infinite loop.
390 curKey = nextKey;
391 }
392 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700393 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800394 res = deleteMapEntry(mUidStatsMap, &nextKey);
395 if (res < 0 && errno != ENOENT) {
396 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
397 strerror(errno));
398 curKey = nextKey;
399 continue;
400 }
Chenbo Fengeac6c472018-02-05 15:06:23 -0800401 removedStatsTotal.rxPackets += old_stats.rxPackets;
402 removedStatsTotal.rxBytes += old_stats.rxBytes;
403 removedStatsTotal.txPackets += old_stats.txPackets;
404 removedStatsTotal.txBytes += old_stats.txBytes;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800405 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700406 curKey = nextKey;
407 }
408 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800409
410 res = writeToMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal, BPF_ANY);
411 if (res) {
412 res = -errno;
413 ALOGE("Failed to add deleting stats to removed uid: %s", strerror(errno));
414 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700415 return res;
416}
417
Chenbo Feng7e974052018-02-28 22:57:21 -0800418int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
419 int res = 0;
420 if (!ebpfSupported) return res;
421
422 char ifaceName[IFNAMSIZ];
423 if (ifaceIndex == 0) {
424 ALOGE("Unknow interface %s(%d)", name, ifaceIndex);
425 return -1;
426 }
427
428 strlcpy(ifaceName, name, sizeof(ifaceName));
429 res = writeToMapEntry(mIfaceIndexNameMap, &ifaceIndex, ifaceName, BPF_ANY);
430 if (res) {
431 res = -errno;
432 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(errno));
433 }
434 return res;
435}
436
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800437bool TrafficController::checkBpfStatsEnable() {
438 return ebpfSupported;
439}
440
Chenbo Fengf2759682017-10-10 17:31:57 -0700441} // namespace net
442} // namespace android