blob: 2db7d4249ec9599b3ef19f6bd7d1ea80a624a3cb [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 Feng33cc1032017-10-23 15:16:37 -070032#include <sys/utsname.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080033#include <unordered_set>
34#include <vector>
35
36#include <android-base/stringprintf.h>
37#include <android-base/unique_fd.h>
38#include <netdutils/StatusOr.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070039
Chenbo Feng116d0552017-12-04 17:25:19 -080040#include <netdutils/Misc.h>
41#include <netdutils/Syscalls.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070042#include "BpfProgSets.h"
Chenbo Fengf2759682017-10-10 17:31:57 -070043#include "TrafficController.h"
Chenbo Fengc10a8a42017-12-15 13:56:33 -080044#include "bpf/BpfUtils.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080045
46#include "NetlinkListener.h"
Chenbo Feng33cc1032017-10-23 15:16:37 -070047#include "qtaguid/qtaguid.h"
Chenbo Fengf2759682017-10-10 17:31:57 -070048
Chenbo Fengc10a8a42017-12-15 13:56:33 -080049using namespace android::bpf;
Chenbo Fengf2759682017-10-10 17:31:57 -070050using namespace android::net::bpf_prog;
51
52namespace android {
53namespace net {
54
Chenbo Fengc10a8a42017-12-15 13:56:33 -080055using base::StringPrintf;
56using base::unique_fd;
Chenbo Feng116d0552017-12-04 17:25:19 -080057using netdutils::extract;
58using netdutils::Slice;
59using netdutils::sSyscalls;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080060using netdutils::Status;
61using netdutils::statusFromErrno;
62using netdutils::StatusOr;
Chenbo Feng116d0552017-12-04 17:25:19 -080063using netdutils::status::ok;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080064
65Status TrafficController::loadAndAttachProgram(bpf_attach_type type, const char* path,
66 const char* name, base::unique_fd& cg_fd) {
67 base::unique_fd fd;
68 int ret = access(path, R_OK);
69 if (ret == 0) {
70 // The program already exist and we can access it.
71 return netdutils::status::ok;
72 }
73
74 if (errno != ENOENT) {
75 // The program exist but we cannot access it.
76 return statusFromErrno(errno, StringPrintf("Cannot access %s at path: %s", name, path));
77 }
78
79 // Program does not exist yet. Load, attach and pin it.
80 if (type == BPF_CGROUP_INET_EGRESS) {
81 fd.reset(loadEgressProg(mCookieTagMap.get(), mUidStatsMap.get(), mTagStatsMap.get(),
82 mUidCounterSetMap.get()));
83 } else {
84 fd.reset(loadIngressProg(mCookieTagMap.get(), mUidStatsMap.get(), mTagStatsMap.get(),
85 mUidCounterSetMap.get()));
86 }
87 if (fd < 0) {
88 return statusFromErrno(errno, StringPrintf("load %s failed", name));
89 }
90
91 ret = attachProgram(type, fd, cg_fd);
92 if (ret) {
93 return statusFromErrno(errno, StringPrintf("%s attach failed", name));
94 }
95
96 ret = mapPin(fd, path);
97 if (ret) {
98 return statusFromErrno(errno, StringPrintf("Pin %s as file failed(%s)", name, path));
99 }
100 return netdutils::status::ok;
101}
102
Chenbo Feng116d0552017-12-04 17:25:19 -0800103constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
104constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
105
106StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener() {
107 const auto& sys = sSyscalls.get();
108 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
109 const int domain = AF_NETLINK;
110 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
111 const int protocol = NETLINK_INET_DIAG;
112 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
113
114 sockaddr_nl addr = {
115 .nl_family = AF_NETLINK,
116 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
117 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
118 RETURN_IF_NOT_OK(sys.bind(sock, addr));
119
120 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
121 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
122
123 std::unique_ptr<NetlinkListenerInterface> listener =
124 std::make_unique<NetlinkListener>(std::move(event), std::move(sock));
125
126 return listener;
127}
128
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800129Status TrafficController::start() {
Chenbo Fengf2759682017-10-10 17:31:57 -0700130 int ret;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700131 struct utsname buf;
132 int kernel_version_major;
133 int kernel_version_minor;
134
135 ret = uname(&buf);
136 if (ret) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800137 return statusFromErrno(errno, "Get system information failed");
Chenbo Feng33cc1032017-10-23 15:16:37 -0700138 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800139
140 char dummy;
141 ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy);
142 if (ret >= 2 &&
143 ((kernel_version_major == 4 && kernel_version_minor >= 9) || (kernel_version_major > 4))) {
Chenbo Feng33cc1032017-10-23 15:16:37 -0700144 // Turn off the eBPF feature temporarily since the selinux rules and kernel changes are not
145 // landed yet.
146 // TODO: turn back on when all the other dependencies are ready.
147 ebpfSupported = false;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800148 return netdutils::status::ok;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700149 } else {
150 ebpfSupported = false;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800151 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700152 }
153
154 /* When netd restart from a crash without total system reboot, the program
155 * is still attached to the cgroup, detach it so the program can be freed
156 * and we can load and attach new program into the target cgroup.
157 *
158 * TODO: Scrape existing socket when run-time restart and clean up the map
159 * if the socket no longer exist
160 */
161
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800162 ALOGI("START to load TrafficController");
163 base::unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
Chenbo Fengf2759682017-10-10 17:31:57 -0700164 if (cg_fd < 0) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800165 return statusFromErrno(errno, "Failed to open the cgroup directory");
Chenbo Fengf2759682017-10-10 17:31:57 -0700166 }
167
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800168 ASSIGN_OR_RETURN(mCookieTagMap,
169 setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
170 COOKIE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
Chenbo Fengf2759682017-10-10 17:31:57 -0700171
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800172 // Allow both netd and system server to obtain map fd from the path. Chown the group to
173 // net_bw_acct does not grant all process in that group the permission to access bpf maps. They
174 // still need correct sepolicy to read/write the map. And only system_server and netd have that
175 // permission for now.
176 ret = chown(COOKIE_UID_MAP_PATH, AID_ROOT, AID_NET_BW_ACCT);
Chenbo Fengf2759682017-10-10 17:31:57 -0700177 if (ret) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800178 return statusFromErrno(errno, "change cookieTagMap group failed.");
179 }
180 ret = chmod(COOKIE_UID_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
181 if (ret) {
182 return statusFromErrno(errno, "change cookieTagMap mode failed.");
Chenbo Fengf2759682017-10-10 17:31:57 -0700183 }
184
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800185 ASSIGN_OR_RETURN(mUidCounterSetMap,
186 setUpBPFMap(sizeof(uint32_t), sizeof(uint32_t), UID_COUNTERSET_MAP_SIZE,
187 UID_COUNTERSET_MAP_PATH, BPF_MAP_TYPE_HASH));
188 // Only netd can access the file.
189 ret = chmod(UID_COUNTERSET_MAP_PATH, S_IRWXU);
Chenbo Fengf2759682017-10-10 17:31:57 -0700190 if (ret) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800191 return statusFromErrno(errno, "change uidCounterSetMap mode failed.");
Chenbo Fengf2759682017-10-10 17:31:57 -0700192 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800193
194 ASSIGN_OR_RETURN(mUidStatsMap,
195 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct Stats), UID_STATS_MAP_SIZE,
196 UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
197 // Change the file mode of pinned map so both netd and system server can get the map fd
198 // from it.
199 ret = chown(UID_STATS_MAP_PATH, AID_ROOT, AID_NET_BW_ACCT);
200 if (ret) {
201 return statusFromErrno(errno, "change uidStatsMap group failed.");
202 }
203 ret = chmod(UID_STATS_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
204 if (ret) {
205 return statusFromErrno(errno, "change uidStatsMap mode failed.");
206 }
207
208 ASSIGN_OR_RETURN(mTagStatsMap,
209 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct Stats), TAG_STATS_MAP_SIZE,
210 TAG_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
211 // Change the file mode of pinned map so both netd and system server can get the map fd
212 // from the path.
213 ret = chown(TAG_STATS_MAP_PATH, AID_ROOT, AID_NET_BW_STATS);
214 if (ret) {
215 return statusFromErrno(errno, "change tagStatsMap group failed.");
216 }
217 ret = chmod(TAG_STATS_MAP_PATH, S_IRWXU | S_IRGRP | S_IWGRP);
218 if (ret) {
219 return statusFromErrno(errno, "change tagStatsMap mode failed.");
220 }
221
Chenbo Feng116d0552017-12-04 17:25:19 -0800222 auto result = makeSkDestroyListener();
223 if (!isOk(result)) {
224 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
225 } else {
226 mSkDestroyListener = std::move(result.value());
227 }
228 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
229 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
230 inet_diag_msg diagmsg = {};
231 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
232 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
233 return;
234 }
235 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
236 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
237
238 deleteMapEntry(mCookieTagMap, &sock_cookie);
239 };
240 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
241
242 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
243 // properly.
244 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
245 // Ignore NLMSG_DONE messages
246 inet_diag_msg diagmsg = {};
247 extract(msg, diagmsg);
248 };
249 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
250
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800251 RETURN_IF_NOT_OK(loadAndAttachProgram(BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH,
252 "Ingress_prog", cg_fd));
253 return loadAndAttachProgram(BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH, "egress_prog", cg_fd);
Chenbo Fengf2759682017-10-10 17:31:57 -0700254}
255
256uint64_t getSocketCookie(int sockFd) {
257 uint64_t sock_cookie;
258 socklen_t cookie_len = sizeof(sock_cookie);
259 int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len);
260 if (res < 0) {
261 res = -errno;
262 ALOGE("Failed to get socket cookie: %s\n", strerror(errno));
263 errno = -res;
264 // 0 is an invalid cookie. See INET_DIAG_NOCOOKIE.
265 return 0;
266 }
267 return sock_cookie;
268}
269
270int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800271 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
272 if (!ebpfSupported) return 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700273
Chenbo Fengf2759682017-10-10 17:31:57 -0700274 uint64_t sock_cookie = getSocketCookie(sockFd);
275 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
276 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
277
278 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
279 // flag so it will insert a new entry to the map if that value doesn't exist
280 // yet. And update the tag if there is already a tag stored. Since the eBPF
281 // program in kernel only read this map, and is protected by rcu read lock. It
282 // should be fine to cocurrently update the map while eBPF program is running.
283 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
284 if (res < 0) {
285 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800286 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700287 }
288
289 return res;
290}
291
292int TrafficController::untagSocket(int sockFd) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800293 if (legacy_untagSocket(sockFd)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700294 if (!ebpfSupported) return 0;
Chenbo Fengf2759682017-10-10 17:31:57 -0700295 uint64_t sock_cookie = getSocketCookie(sockFd);
296
297 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
298 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
299 if (res) {
300 res = -errno;
301 ALOGE("Failed to untag socket: %s\n", strerror(errno));
302 }
303 return res;
304}
305
306int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
307 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700308 int res;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800309 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
310 if (!ebpfSupported) return 0;
311
312 // The default counter set for all uid is 0, so deleting the current counterset for that uid
313 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700314 if (counterSetNum == 0) {
315 res = deleteMapEntry(mUidCounterSetMap, &uid);
316 if (res == 0 || (res == -1 && errno == ENOENT)) {
317 return 0;
318 } else {
319 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
320 return -errno;
321 }
322 }
323
324 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
325 if (res < 0) {
326 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800327 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700328 }
329 return res;
330}
331
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800332// TODO: Add a lock for delete tag Data so when several request for different uid comes in, they do
333// not race with each other.
Chenbo Fengf2759682017-10-10 17:31:57 -0700334int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
335 int res = 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700336
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800337 if (legacy_deleteTagData(tag, uid)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700338 if (!ebpfSupported) return 0;
339
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800340 uint64_t curCookie = NONEXIST_COOKIE;
Chenbo Fengf2759682017-10-10 17:31:57 -0700341 uint64_t nextCookie = 0;
342 UidTag tmp_uidtag;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800343 std::vector<uint64_t> cookieList;
344 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
345 // the tags related to the uid if the tag is 0, we start the map iteration with a cookie of
346 // INET_DIAG_NOCOOKIE because it's guaranteed that that will not be in the map.
347 while (getNextMapKey(mCookieTagMap, &curCookie, &nextCookie) != -1) {
348 res = findMapEntry(mCookieTagMap, &nextCookie, &tmp_uidtag);
Chenbo Fengf2759682017-10-10 17:31:57 -0700349 if (res < 0) {
350 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800351 ALOGE("Failed to get tag info(cookie = %" PRIu64 ": %s\n", nextCookie, strerror(errno));
352 // Continue to look for next entry.
353 curCookie = nextCookie;
354 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700355 }
356
357 if (tmp_uidtag.uid == uid && (tmp_uidtag.tag == tag || tag == 0)) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800358 res = deleteMapEntry(mCookieTagMap, &nextCookie);
359 if (res < 0 && errno != ENOENT) {
Chenbo Fengf2759682017-10-10 17:31:57 -0700360 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800361 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", nextCookie,
362 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700363 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800364 } else {
365 // Move forward to next cookie in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700366 curCookie = nextCookie;
367 }
368 }
369
370 // 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 -0800371 // combination. Or all tag stats under that uid if the target tag is 0. The initial key is
372 // set to the nonexist_statskey because it will never be in the map, and thus getNextMapKey will
373 // return 0 and set nextKey to the first key in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700374 struct StatsKey curKey, nextKey;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800375 curKey = NONEXIST_STATSKEY;
376 while (getNextMapKey(mTagStatsMap, &curKey, &nextKey) != -1) {
377 if (nextKey.uid == uid && (nextKey.tag == tag || tag == 0)) {
378 res = deleteMapEntry(mTagStatsMap, &nextKey);
379 if (res < 0 && errno != ENOENT) {
380 // Skip the current entry if unexpected error happened.
381 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
382 strerror(errno));
383 curKey = nextKey;
Chenbo Fengf2759682017-10-10 17:31:57 -0700384 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800385 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700386 curKey = nextKey;
387 }
388 }
389
390 // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
391 // need to delete the stats stored in uidStatsMap
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800392 if (tag != 0) return 0;
393
394 res = deleteMapEntry(mUidCounterSetMap, &uid);
395 if (res < 0 && errno != ENOENT) {
396 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
397 }
398
399 // For the uid stats deleted from the map, move them into a special
400 // removed uid entry. The removed uid is stored in uid 0, tag 0 and
401 // counterSet as COUNTERSETS_LIMIT.
402 StatsKey removedStatsKey = {0, 0, COUNTERSETS_LIMIT, 0};
403 Stats removedStatsTotal = {};
404 res = findMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal);
405 if (res < 0 && errno != ENOENT) {
406 ALOGE("Failed to get stats of removed uid: %s", strerror(errno));
407 }
408
409 curKey = NONEXIST_STATSKEY;
410 while (getNextMapKey(mUidStatsMap, &curKey, &nextKey) != -1) {
411 if (nextKey.uid == uid) {
412 Stats old_stats = {};
413 res = findMapEntry(mUidStatsMap, &nextKey, &old_stats);
414 if (res < 0) {
415 if (errno != ENOENT) {
416 // if errno is ENOENT Somebody else deleted nextKey. Lookup the next key from
417 // curKey. If we have other error. Skip this key to avoid an infinite loop.
418 curKey = nextKey;
419 }
420 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700421 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800422 res = deleteMapEntry(mUidStatsMap, &nextKey);
423 if (res < 0 && errno != ENOENT) {
424 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
425 strerror(errno));
426 curKey = nextKey;
427 continue;
428 }
429 removedStatsTotal.rxTcpPackets += old_stats.rxTcpPackets;
430 removedStatsTotal.rxTcpBytes += old_stats.rxTcpBytes;
431 removedStatsTotal.txTcpPackets += old_stats.txTcpPackets;
432 removedStatsTotal.txTcpBytes += old_stats.txTcpBytes;
433 removedStatsTotal.rxUdpPackets += old_stats.rxUdpPackets;
434 removedStatsTotal.rxUdpBytes += old_stats.rxUdpBytes;
435 removedStatsTotal.txUdpPackets += old_stats.txUdpPackets;
436 removedStatsTotal.txUdpBytes += old_stats.txUdpBytes;
437 removedStatsTotal.rxOtherPackets += old_stats.rxOtherPackets;
438 removedStatsTotal.rxOtherBytes += old_stats.rxOtherBytes;
439 removedStatsTotal.txOtherPackets += old_stats.txOtherPackets;
440 removedStatsTotal.txOtherBytes += old_stats.txOtherBytes;
441 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700442 curKey = nextKey;
443 }
444 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800445
446 res = writeToMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal, BPF_ANY);
447 if (res) {
448 res = -errno;
449 ALOGE("Failed to add deleting stats to removed uid: %s", strerror(errno));
450 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700451 return res;
452}
453
Chenbo Fengf2759682017-10-10 17:31:57 -0700454} // namespace net
455} // namespace android