blob: 9535efe2b82f17c26d476177e82e6dcf38f9a117 [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"
18
Chenbo Feng33cc1032017-10-23 15:16:37 -070019#include <inttypes.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070020#include <linux/bpf.h>
21#include <linux/if_ether.h>
22#include <linux/in.h>
23#include <linux/inet_diag.h>
Chenbo Feng116d0552017-12-04 17:25:19 -080024#include <linux/netlink.h>
25#include <linux/sock_diag.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070026#include <linux/unistd.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080027#include <net/if.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070028#include <stdlib.h>
29#include <string.h>
30#include <sys/socket.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080031#include <sys/stat.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080032#include <sys/types.h>
Chenbo Feng33cc1032017-10-23 15:16:37 -070033#include <sys/utsname.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080034#include <sys/wait.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080035#include <unordered_set>
36#include <vector>
37
38#include <android-base/stringprintf.h>
39#include <android-base/unique_fd.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080040#include <logwrap/logwrap.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080041#include <netdutils/StatusOr.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070042
Chenbo Feng116d0552017-12-04 17:25:19 -080043#include <netdutils/Misc.h>
44#include <netdutils/Syscalls.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070045#include "TrafficController.h"
Chenbo Fengc10a8a42017-12-15 13:56:33 -080046#include "bpf/BpfUtils.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080047
48#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 Feng116d0552017-12-04 17:25:19 -0800162 auto result = makeSkDestroyListener();
163 if (!isOk(result)) {
164 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
165 } else {
166 mSkDestroyListener = std::move(result.value());
167 }
168 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
169 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
170 inet_diag_msg diagmsg = {};
171 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
172 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
173 return;
174 }
175 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
176 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
177
178 deleteMapEntry(mCookieTagMap, &sock_cookie);
179 };
180 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
181
182 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
183 // properly.
184 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
185 // Ignore NLMSG_DONE messages
186 inet_diag_msg diagmsg = {};
187 extract(msg, diagmsg);
188 };
189 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
190
Chenbo Feng05393d82018-01-09 15:18:43 -0800191 int* status = nullptr;
192
193 std::vector<const char*> prog_args{
194 "/system/bin/bpfloader",
195 };
196 ret = access(BPF_INGRESS_PROG_PATH, R_OK);
197 if (ret != 0 && errno == ENOENT) {
198 prog_args.push_back((char*)"-i");
199 }
200 ret = access(BPF_EGRESS_PROG_PATH, R_OK);
201 if (ret != 0 && errno == ENOENT) {
202 prog_args.push_back((char*)"-e");
203 }
204
205 if (prog_args.size() == 1) {
206 // both program are loaded already.
207 return netdutils::status::ok;
208 }
209
210 prog_args.push_back(nullptr);
211 ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
212 if (ret) {
213 ret = errno;
214 ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
215 return statusFromErrno(ret, "run bpf loader failed");
216 }
217 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700218}
219
Chenbo Fengf2759682017-10-10 17:31:57 -0700220int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800221 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
222 if (!ebpfSupported) return 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700223
Chenbo Fengf2759682017-10-10 17:31:57 -0700224 uint64_t sock_cookie = getSocketCookie(sockFd);
225 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
226 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
227
228 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
229 // flag so it will insert a new entry to the map if that value doesn't exist
230 // yet. And update the tag if there is already a tag stored. Since the eBPF
231 // program in kernel only read this map, and is protected by rcu read lock. It
232 // should be fine to cocurrently update the map while eBPF program is running.
233 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
234 if (res < 0) {
235 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800236 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700237 }
238
239 return res;
240}
241
242int TrafficController::untagSocket(int sockFd) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800243 if (legacy_untagSocket(sockFd)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700244 if (!ebpfSupported) return 0;
Chenbo Fengf2759682017-10-10 17:31:57 -0700245 uint64_t sock_cookie = getSocketCookie(sockFd);
246
247 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
248 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
249 if (res) {
250 res = -errno;
251 ALOGE("Failed to untag socket: %s\n", strerror(errno));
252 }
253 return res;
254}
255
256int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
257 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700258 int res;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800259 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
260 if (!ebpfSupported) return 0;
261
262 // The default counter set for all uid is 0, so deleting the current counterset for that uid
263 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700264 if (counterSetNum == 0) {
265 res = deleteMapEntry(mUidCounterSetMap, &uid);
266 if (res == 0 || (res == -1 && errno == ENOENT)) {
267 return 0;
268 } else {
269 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
270 return -errno;
271 }
272 }
273
274 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
275 if (res < 0) {
276 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800277 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700278 }
279 return res;
280}
281
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800282// TODO: Add a lock for delete tag Data so when several request for different uid comes in, they do
283// not race with each other.
Chenbo Fengf2759682017-10-10 17:31:57 -0700284int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
285 int res = 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700286
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800287 if (legacy_deleteTagData(tag, uid)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700288 if (!ebpfSupported) return 0;
289
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800290 uint64_t curCookie = NONEXIST_COOKIE;
Chenbo Fengf2759682017-10-10 17:31:57 -0700291 uint64_t nextCookie = 0;
292 UidTag tmp_uidtag;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800293 std::vector<uint64_t> cookieList;
294 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
295 // the tags related to the uid if the tag is 0, we start the map iteration with a cookie of
296 // INET_DIAG_NOCOOKIE because it's guaranteed that that will not be in the map.
297 while (getNextMapKey(mCookieTagMap, &curCookie, &nextCookie) != -1) {
298 res = findMapEntry(mCookieTagMap, &nextCookie, &tmp_uidtag);
Chenbo Fengf2759682017-10-10 17:31:57 -0700299 if (res < 0) {
300 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800301 ALOGE("Failed to get tag info(cookie = %" PRIu64 ": %s\n", nextCookie, strerror(errno));
302 // Continue to look for next entry.
303 curCookie = nextCookie;
304 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700305 }
306
307 if (tmp_uidtag.uid == uid && (tmp_uidtag.tag == tag || tag == 0)) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800308 res = deleteMapEntry(mCookieTagMap, &nextCookie);
309 if (res < 0 && errno != ENOENT) {
Chenbo Fengf2759682017-10-10 17:31:57 -0700310 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800311 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", nextCookie,
312 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700313 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800314 } else {
315 // Move forward to next cookie in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700316 curCookie = nextCookie;
317 }
318 }
319
320 // 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 -0800321 // combination. Or all tag stats under that uid if the target tag is 0. The initial key is
322 // set to the nonexist_statskey because it will never be in the map, and thus getNextMapKey will
323 // return 0 and set nextKey to the first key in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700324 struct StatsKey curKey, nextKey;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800325 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800326 while (getNextMapKey(mTagStatsMap, &curKey, &nextKey) != -1) {
327 if (nextKey.uid == uid && (nextKey.tag == tag || tag == 0)) {
328 res = deleteMapEntry(mTagStatsMap, &nextKey);
329 if (res < 0 && errno != ENOENT) {
330 // Skip the current entry if unexpected error happened.
331 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
332 strerror(errno));
333 curKey = nextKey;
Chenbo Fengf2759682017-10-10 17:31:57 -0700334 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800335 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700336 curKey = nextKey;
337 }
338 }
339
340 // 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 -0800341 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800342 if (tag != 0) return 0;
343
344 res = deleteMapEntry(mUidCounterSetMap, &uid);
345 if (res < 0 && errno != ENOENT) {
346 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
347 }
348
349 // For the uid stats deleted from the map, move them into a special
350 // removed uid entry. The removed uid is stored in uid 0, tag 0 and
351 // counterSet as COUNTERSETS_LIMIT.
352 StatsKey removedStatsKey = {0, 0, COUNTERSETS_LIMIT, 0};
Chenbo Fengf43bf812017-12-15 18:27:22 -0800353 StatsValue removedStatsTotal = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800354 res = findMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal);
355 if (res < 0 && errno != ENOENT) {
356 ALOGE("Failed to get stats of removed uid: %s", strerror(errno));
357 }
358
Chenbo Fengf43bf812017-12-15 18:27:22 -0800359 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800360 while (getNextMapKey(mUidStatsMap, &curKey, &nextKey) != -1) {
361 if (nextKey.uid == uid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800362 StatsValue old_stats = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800363 res = findMapEntry(mUidStatsMap, &nextKey, &old_stats);
364 if (res < 0) {
365 if (errno != ENOENT) {
366 // if errno is ENOENT Somebody else deleted nextKey. Lookup the next key from
367 // curKey. If we have other error. Skip this key to avoid an infinite loop.
368 curKey = nextKey;
369 }
370 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700371 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800372 res = deleteMapEntry(mUidStatsMap, &nextKey);
373 if (res < 0 && errno != ENOENT) {
374 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
375 strerror(errno));
376 curKey = nextKey;
377 continue;
378 }
379 removedStatsTotal.rxTcpPackets += old_stats.rxTcpPackets;
380 removedStatsTotal.rxTcpBytes += old_stats.rxTcpBytes;
381 removedStatsTotal.txTcpPackets += old_stats.txTcpPackets;
382 removedStatsTotal.txTcpBytes += old_stats.txTcpBytes;
383 removedStatsTotal.rxUdpPackets += old_stats.rxUdpPackets;
384 removedStatsTotal.rxUdpBytes += old_stats.rxUdpBytes;
385 removedStatsTotal.txUdpPackets += old_stats.txUdpPackets;
386 removedStatsTotal.txUdpBytes += old_stats.txUdpBytes;
387 removedStatsTotal.rxOtherPackets += old_stats.rxOtherPackets;
388 removedStatsTotal.rxOtherBytes += old_stats.rxOtherBytes;
389 removedStatsTotal.txOtherPackets += old_stats.txOtherPackets;
390 removedStatsTotal.txOtherBytes += old_stats.txOtherBytes;
391 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700392 curKey = nextKey;
393 }
394 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800395
396 res = writeToMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal, BPF_ANY);
397 if (res) {
398 res = -errno;
399 ALOGE("Failed to add deleting stats to removed uid: %s", strerror(errno));
400 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700401 return res;
402}
403
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800404bool TrafficController::checkBpfStatsEnable() {
405 return ebpfSupported;
406}
407
Chenbo Fengf2759682017-10-10 17:31:57 -0700408} // namespace net
409} // namespace android