/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <bpf/BpfMap.h> namespace android { namespace bpf { // TODO: set this to a proper value based on the map size; constexpr int TAG_STATS_MAP_SOFT_LIMIT = 3; constexpr int UID_ALL = -1; constexpr int TAG_ALL = -1; constexpr int TAG_NONE = 0; constexpr int SET_ALL = -1; constexpr int SET_DEFAULT = 0; constexpr int SET_FOREGROUND = 1; // The limit for stats received by a unknown interface; constexpr const int64_t MAX_UNKNOWN_IFACE_BYTES = 100 * 1000; // This is a JNI ABI and is used by // framework/base/core/jni/com_android_internal_net_NetworkStatsFactory.cpp // make sure it is consistent with the JNI code before changing this. struct stats_line { char iface[32]; int32_t uid; int32_t set; int32_t tag; int64_t rxBytes; int64_t rxPackets; int64_t txBytes; int64_t txPackets; }; // For test only int bpfGetUidStatsInternal(uid_t uid, struct Stats* stats, const BpfMap<uint32_t, StatsValue>& appUidStatsMap); // For test only int bpfGetIfaceStatsInternal(const char* iface, Stats* stats, const BpfMap<uint32_t, StatsValue>& ifaceStatsMap, const BpfMap<uint32_t, IfaceValue>& ifaceNameMap); // For test only int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap); // For test only int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap); // For test only template <class Key> int getIfaceNameFromMap(const BpfMap<uint32_t, IfaceValue>& ifaceMap, const BpfMap<Key, StatsValue>& statsMap, uint32_t ifaceIndex, char* ifname, const Key& curKey, int64_t* unknownIfaceBytesTotal) { auto iface = ifaceMap.readValue(ifaceIndex); if (!isOk(iface)) { maybeLogUnknownIface(ifaceIndex, statsMap, curKey, unknownIfaceBytesTotal); return -ENODEV; } strlcpy(ifname, iface.value().name, sizeof(IfaceValue)); return 0; } template <class Key> void maybeLogUnknownIface(int ifaceIndex, const BpfMap<Key, StatsValue>& statsMap, const Key& curKey, int64_t* unknownIfaceBytesTotal) { // Have we already logged an error? if (*unknownIfaceBytesTotal == -1) { return; } // Are we undercounting enough data to be worth logging? auto statsEntry = statsMap.readValue(curKey); if (!netdutils::isOk(statsEntry)) { // No data is being undercounted. return; } *unknownIfaceBytesTotal += (statsEntry.value().rxBytes + statsEntry.value().txBytes); if (*unknownIfaceBytesTotal >= MAX_UNKNOWN_IFACE_BYTES) { ALOGE("Unknown name for ifindex %d with more than %" PRId64 " bytes of traffic", ifaceIndex, *unknownIfaceBytesTotal); *unknownIfaceBytesTotal = -1; } } // For test only int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines, const BpfMap<uint32_t, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap); int bpfGetUidStats(uid_t uid, struct Stats* stats); int bpfGetIfaceStats(const char* iface, struct Stats* stats); int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid); int parseBpfNetworkStatsDev(std::vector<stats_line>* lines); int cleanStatsMap(); } // namespace bpf } // namespace android