Refactor bpf map iterate process
The bpf map read process is very similiar for different kind of maps. It
can be generalized into a single generic function and take callback
functions from the caller. The caller handles the map entry read out
from the generic map iterate function by the lambda expression passed
in.
Bug: 72111305
Test: ./libbpf_test
run cts -m CtsNetTestCases -t android.net.cts.TrafficStatsTest
Change-Id: I244f306d05f6f5dab36861fc66375963869ea150
diff --git a/libbpf/BpfNetworkStats.cpp b/libbpf/BpfNetworkStats.cpp
index abd0ff6..f43178c 100644
--- a/libbpf/BpfNetworkStats.cpp
+++ b/libbpf/BpfNetworkStats.cpp
@@ -45,24 +45,22 @@
static constexpr uint32_t BPF_OPEN_FLAGS = BPF_F_RDONLY;
int bpfGetUidStatsInternal(uid_t uid, Stats* stats, const base::unique_fd& map_fd) {
- struct StatsKey curKey, nextKey;
- curKey = NONEXISTENT_STATSKEY;
- while (bpf::getNextMapKey(map_fd, &curKey, &nextKey) != -1) {
- curKey = nextKey;
- if (curKey.uid == uid) {
- StatsValue statsEntry;
- if (bpf::findMapEntry(map_fd, &curKey, &statsEntry) < 0) {
- return -errno;
- }
- stats->rxPackets += statsEntry.rxPackets;
- stats->txPackets += statsEntry.txPackets;
- stats->rxBytes += statsEntry.rxBytes;
- stats->txBytes += statsEntry.txBytes;
+ struct StatsKey nonExistentKey = NONEXISTENT_STATSKEY;
+ struct StatsValue dummyValue;
+ auto processUidStats = [uid, stats](void *key, const base::unique_fd& map_fd) {
+ if (((StatsKey *) key)->uid != uid) {
+ return 0;
}
- }
- // Return errno if getNextMapKey return error before hit to the end of the map.
- if (errno != ENOENT) return -errno;
- return 0;
+ StatsValue statsEntry;
+ int ret = bpf::findMapEntry(map_fd, key, &statsEntry);
+ if (ret) return -errno;
+ stats->rxPackets += statsEntry.rxPackets;
+ stats->txPackets += statsEntry.txPackets;
+ stats->rxBytes += statsEntry.rxBytes;
+ stats->txBytes += statsEntry.txBytes;
+ return 0;
+ };
+ return bpfIterateMap(nonExistentKey, dummyValue, map_fd, processUidStats);
}
int bpfGetUidStats(uid_t uid, Stats* stats) {
@@ -147,96 +145,76 @@
return 0;
}
-int parseBpfUidStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitUid,
- const base::unique_fd& statsMapFd, const base::unique_fd& ifaceMapFd) {
- struct StatsKey curKey, nextKey;
- curKey = NONEXISTENT_STATSKEY;
+int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
+ const std::vector<std::string>& limitIfaces, int limitTag,
+ int limitUid, const base::unique_fd& statsMapFd,
+ const base::unique_fd& ifaceMapFd) {
uint64_t unknownIfaceBytesTotal = 0;
- while (bpf::getNextMapKey(statsMapFd, &curKey, &nextKey) != -1) {
- curKey = nextKey;
- char ifname[IFNAMSIZ];
- // The data entry in uid map that stores removed uid stats use 0 as the
- // iface. Just skip when seen.
- if (curKey.ifaceIndex == 0 ||
- getIfaceNameFromMap(ifaceMapFd, statsMapFd, ifname, curKey, &unknownIfaceBytesTotal)) {
- continue;
- }
- std::string ifnameStr(ifname);
- if (limitIfaces.size() > 0 &&
- std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
- // Nothing matched; skip this line.
- continue;
- }
- if (limitUid != UID_ALL && limitUid != int(curKey.uid)) continue;
- StatsValue statsEntry;
- if (bpf::findMapEntry(statsMapFd, &curKey, &statsEntry) < 0) {
- int ret = -errno;
- ALOGE("get map statsEntry failed: %s", strerror(errno));
- return ret;
- }
- lines->push_back(populateStatsEntry(curKey, statsEntry, ifname));
- }
- return 0;
-}
-
-int parseBpfTagStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitTag, int limitUid,
- const base::unique_fd& statsMapFd, const base::unique_fd& ifaceMapFd) {
- struct StatsKey curKey, nextKey;
- curKey = NONEXISTENT_STATSKEY;
- uint64_t unknownIfaceBytesTotal = 0;
- while (bpf::getNextMapKey(statsMapFd, &curKey, &nextKey) != -1) {
- curKey = nextKey;
+ struct StatsKey nonExistentKey = NONEXISTENT_STATSKEY;
+ struct StatsValue dummyValue;
+ auto processDetailUidStats = [lines, &limitIfaces, limitTag, limitUid,
+ &unknownIfaceBytesTotal, &ifaceMapFd]
+ (void* key, const base::unique_fd& statsMapFd) {
+ struct StatsKey curKey = * (struct StatsKey*)key;
char ifname[IFNAMSIZ];
if (getIfaceNameFromMap(ifaceMapFd, statsMapFd, ifname, curKey, &unknownIfaceBytesTotal)) {
- continue;
+ return 0;
}
std::string ifnameStr(ifname);
if (limitIfaces.size() > 0 &&
std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
// Nothing matched; skip this line.
- continue;
+ return 0;
}
- if ((limitTag != TAG_ALL && uint32_t(limitTag) != (curKey.tag)) ||
- (limitUid != UID_ALL && uint32_t(limitUid) != curKey.uid))
- continue;
+ if (limitTag != TAG_ALL && uint32_t(limitTag) != curKey.tag) {
+ return 0;
+ }
+ if (limitUid != UID_ALL && uint32_t(limitUid) != curKey.uid) {
+ return 0;
+ }
StatsValue statsEntry;
if (bpf::findMapEntry(statsMapFd, &curKey, &statsEntry) < 0) return -errno;
lines->push_back(populateStatsEntry(curKey, statsEntry, ifname));
- }
- if (errno != ENOENT) return -errno;
- return 0;
+ return 0;
+ };
+ return bpfIterateMap(nonExistentKey, dummyValue, statsMapFd, processDetailUidStats);
}
int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
const std::vector<std::string>& limitIfaces, int limitTag,
int limitUid) {
- base::unique_fd tagStatsMap(bpf::mapRetrieve(TAG_STATS_MAP_PATH, BPF_OPEN_FLAGS));
int ret = 0;
- if (tagStatsMap < 0) {
- ret = -errno;
- ALOGE("get tagStats map fd failed: %s", strerror(errno));
- return ret;
- }
base::unique_fd ifaceIndexNameMap(bpf::mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
if (ifaceIndexNameMap < 0) {
ret = -errno;
ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
return ret;
}
- ret = parseBpfTagStatsDetail(lines, limitIfaces, limitTag, limitUid, tagStatsMap,
- ifaceIndexNameMap);
- if (ret) return ret;
- if (limitTag == TAG_ALL) {
+ // If the caller did not pass in TAG_NONE, read tag data.
+ if (limitTag != TAG_NONE) {
+ base::unique_fd tagStatsMap(bpf::mapRetrieve(TAG_STATS_MAP_PATH, BPF_OPEN_FLAGS));
+ if (tagStatsMap < 0) {
+ ret = -errno;
+ ALOGE("get tagStats map fd failed: %s", strerror(errno));
+ return ret;
+ }
+ ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
+ tagStatsMap, ifaceIndexNameMap);
+ if (ret) return ret;
+ }
+
+ // If the caller did not pass in a specific tag (i.e., if limitTag is TAG_NONE(0) or
+ // TAG_ALL(-1)) read UID data.
+ if (limitTag == TAG_NONE || limitTag == TAG_ALL) {
base::unique_fd uidStatsMap(bpf::mapRetrieve(UID_STATS_MAP_PATH, BPF_OPEN_FLAGS));
if (uidStatsMap < 0) {
ret = -errno;
ALOGE("Opening map fd from %s failed: %s", UID_STATS_MAP_PATH, strerror(errno));
return ret;
}
- ret = parseBpfUidStatsDetail(lines, limitIfaces, limitUid, uidStatsMap, ifaceIndexNameMap);
+ ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
+ uidStatsMap, ifaceIndexNameMap);
}
return ret;
}