1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <net/if.h>
17#include <vector>
18
19#include "bpf_path.h"
20#include "bpf_def.h"
21#include "bpf_stats.h"
22#include "securec.h"
23#include "netnative_log_wrapper.h"
24#include "net_stats_constants.h"
25
26namespace OHOS::NetManagerStandard {
27namespace {
28constexpr const char *CELLULAR_IFACE = "rmnet0";
29constexpr const char *WIFI_IFACE = "wlan0";
30}
31int32_t NetsysBpfStats::GetNumberFromStatsValue(uint64_t &stats, StatsType statsType, const stats_value &value)
32{
33    switch (statsType) {
34        case StatsType::STATS_TYPE_RX_BYTES:
35            stats = value.rxBytes;
36            break;
37        case StatsType::STATS_TYPE_RX_PACKETS:
38            stats = value.rxPackets;
39            break;
40        case StatsType::STATS_TYPE_TX_BYTES:
41            stats = value.txBytes;
42            break;
43        case StatsType::STATS_TYPE_TX_PACKETS:
44            stats = value.txPackets;
45            break;
46        default:
47            NETNATIVE_LOGE("invalid StatsType type %{public}d", statsType);
48            return STATS_ERR_READ_BPF_FAIL;
49    }
50    return NETSYS_SUCCESS;
51}
52
53int32_t NetsysBpfStats::GetTotalStats(uint64_t &stats, StatsType statsType)
54{
55    stats = 0;
56    BpfMapper<iface_stats_key, iface_stats_value> ifaceStatsMap(IFACE_STATS_MAP_PATH, BPF_F_RDONLY);
57    if (!ifaceStatsMap.IsValid()) {
58        NETNATIVE_LOGE("ifaceStatsMap IsValid");
59        return STATS_ERR_INVALID_IFACE_NAME_MAP;
60    }
61
62    iface_stats_value totalStats = {0};
63    auto keys = ifaceStatsMap.GetAllKeys();
64    for (const auto &k : keys) {
65        iface_stats_value v = {0};
66        if (ifaceStatsMap.Read(k, v) < NETSYS_SUCCESS) {
67            NETNATIVE_LOGE("Read ifaceStatsMap err");
68            return STATS_ERR_READ_BPF_FAIL;
69        }
70        totalStats.rxPackets += v.rxPackets;
71        totalStats.rxBytes += v.rxBytes;
72        totalStats.txPackets += v.txPackets;
73        totalStats.txBytes += v.txBytes;
74    }
75
76    return GetNumberFromStatsValue(stats, statsType, totalStats);
77}
78
79int32_t NetsysBpfStats::GetUidStats(uint64_t &stats, StatsType statsType, uint32_t uid)
80{
81    stats = 0;
82    BpfMapper<app_uid_stats_key, app_uid_stats_value> appUidStatsMap(APP_UID_STATS_MAP_PATH, BPF_F_RDONLY);
83    if (!appUidStatsMap.IsValid()) {
84        return STATS_ERR_INVALID_IFACE_NAME_MAP;
85    }
86
87    app_uid_stats_value uidStats = {0};
88    if (appUidStatsMap.Read(uid, uidStats) < 0) {
89        return STATS_ERR_READ_BPF_FAIL;
90    }
91    return GetNumberFromStatsValue(stats, statsType, uidStats);
92}
93
94int32_t NetsysBpfStats::GetAllSimStatsInfo(std::vector<OHOS::NetManagerStandard::NetStatsInfo> &stats)
95{
96    BpfMapper<stats_key, stats_value> uidSimStatsMap(APP_UID_SIM_STATS_MAP_PATH, BPF_F_RDONLY);
97    if (!uidSimStatsMap.IsValid()) {
98        return STATS_ERR_INVALID_IFACE_NAME_MAP;
99    }
100
101    stats.clear();
102    char if_name[IFNAME_SIZE] = {0};
103    auto keys = uidSimStatsMap.GetAllKeys();
104    for (const auto &k : keys) {
105        stats_value v = {};
106        if (uidSimStatsMap.Read(k, v) < 0) {
107            NETNATIVE_LOGE("Read uid_sim_map err");
108            return STATS_ERR_READ_BPF_FAIL;
109        }
110
111        NetStatsInfo tempStats;
112        tempStats.uid_ = k.uId;
113        if (memset_s(if_name, sizeof(if_name), 0, sizeof(if_name)) != EOK) {
114            return STATS_ERR_READ_BPF_FAIL;
115        }
116
117        char *pName = if_indextoname(k.ifIndex, if_name);
118        if (pName != nullptr) {
119            tempStats.iface_ = pName;
120        }
121        if (k.ifType == IFACE_TYPE_WIFI) {
122            tempStats.iface_ = WIFI_IFACE;
123        } else if (k.ifType == IFACE_TYPE_CELLULAR) {
124            tempStats.iface_ = CELLULAR_IFACE;
125        }
126        tempStats.rxBytes_ = v.rxBytes;
127        tempStats.txBytes_ = v.txBytes;
128        tempStats.rxPackets_ = v.rxPackets;
129        tempStats.txPackets_ = v.txPackets;
130        auto findRet = std::find_if(stats.begin(), stats.end(),
131                                    [&tempStats](const NetStatsInfo &info) { return info.Equals(tempStats); });
132        if (findRet == stats.end()) {
133            stats.push_back(std::move(tempStats));
134        } else {
135            *findRet += tempStats;
136        }
137    }
138
139    return NETSYS_SUCCESS;
140}
141
142int32_t NetsysBpfStats::GetAllStatsInfo(std::vector<OHOS::NetManagerStandard::NetStatsInfo> &stats)
143{
144    BpfMapper<stats_key, stats_value> uidIfaceStatsMap(APP_UID_IF_STATS_MAP_PATH, BPF_F_RDONLY);
145    if (!uidIfaceStatsMap.IsValid()) {
146        return STATS_ERR_INVALID_IFACE_NAME_MAP;
147    }
148
149    stats.clear();
150    char if_name[IFNAME_SIZE] = {0};
151    auto keys = uidIfaceStatsMap.GetAllKeys();
152    for (const auto &k : keys) {
153        stats_value v = {};
154        if (uidIfaceStatsMap.Read(k, v) < 0) {
155            NETNATIVE_LOGE("Read ifaceStatsMap err");
156            return STATS_ERR_READ_BPF_FAIL;
157        }
158
159        NetStatsInfo tempStats;
160        tempStats.uid_ = k.uId;
161        if (memset_s(if_name, sizeof(if_name), 0, sizeof(if_name)) != EOK) {
162            return STATS_ERR_READ_BPF_FAIL;
163        }
164
165        char *pName = if_indextoname(k.ifIndex, if_name);
166        if (pName != nullptr) {
167            tempStats.iface_ = pName;
168        }
169        tempStats.rxBytes_ = v.rxBytes;
170        tempStats.txBytes_ = v.txBytes;
171        tempStats.rxPackets_ = v.rxPackets;
172        tempStats.txPackets_ = v.txPackets;
173        stats.emplace_back(std::move(tempStats));
174    }
175
176    return NETSYS_SUCCESS;
177}
178
179int32_t NetsysBpfStats::DeleteStatsInfo(const std::string &path, uint32_t uid)
180{
181    if (path != APP_UID_IF_STATS_MAP_PATH && path != APP_UID_SIM_STATS_MAP_PATH) {
182        NETNATIVE_LOGI("DeleteStatsInfo invalid path");
183        return NETSYS_SUCCESS;
184    }
185    BpfMapper<stats_key, stats_value> uidStatsMap(path, BPF_ANY);
186    if (!uidStatsMap.IsValid()) {
187        return STATS_ERR_INVALID_IFACE_NAME_MAP;
188    }
189    auto keys = uidStatsMap.GetAllKeys();
190    for (const auto &k : keys) {
191        if (k.uId == uid) {
192            if (uidStatsMap.Delete(k) < 0) {
193                NETNATIVE_LOGE("Delete uidStatsMap err");
194                return STATS_ERR_WRITE_BPF_FAIL;
195            }
196        }
197    }
198    return NETSYS_SUCCESS;
199}
200
201int32_t NetsysBpfStats::GetIfaceStats(uint64_t &stats, const StatsType statsType, const std::string &interfaceName)
202{
203    stats = 0;
204    BpfMapper<iface_stats_key, iface_stats_value> ifaceStatsMap(IFACE_STATS_MAP_PATH, BPF_F_RDONLY);
205    if (!ifaceStatsMap.IsValid()) {
206        return STATS_ERR_INVALID_IFACE_NAME_MAP;
207    }
208
209    auto ifIndex = if_nametoindex(interfaceName.c_str());
210    if (ifIndex <= 0) {
211        return STATS_ERR_GET_IFACE_NAME_FAILED;
212    }
213
214    iface_stats_value ifaceStats = {0};
215    if (ifaceStatsMap.Read(ifIndex, ifaceStats) < 0) {
216        return STATS_ERR_READ_BPF_FAIL;
217    }
218    return GetNumberFromStatsValue(stats, statsType, ifaceStats);
219}
220
221int32_t NetsysBpfStats::GetCookieStats(uint64_t &stats, StatsType statsType, uint64_t cookie)
222{
223    NETNATIVE_LOGI("GetCookieStats start");
224    stats = 0;
225    BpfMapper<socket_cookie_stats_key, app_cookie_stats_value> appUidCookieStatsMap(APP_COOKIE_STATS_MAP_PATH,
226                                                                                    BPF_F_RDONLY);
227    if (!appUidCookieStatsMap.IsValid()) {
228        NETNATIVE_LOGE("GetCookieStats appUidCookieStatsMap is valid");
229        return NETMANAGER_ERR_INTERNAL;
230    }
231
232    app_cookie_stats_value cookieStats = {0};
233    if (appUidCookieStatsMap.Read(cookie, cookieStats) < 0) {
234        NETNATIVE_LOGE("GetCookieStats appUidCookieStatsMap read error");
235        return NETMANAGER_ERR_INTERNAL;
236    }
237
238    int32_t res = GetNumberFromStatsValue(stats, statsType, cookieStats);
239    if (res == STATS_ERR_READ_BPF_FAIL) {
240        NETNATIVE_LOGE("GetCookieStats GetNumberFromStatsValue error");
241        return NETMANAGER_ERR_INTERNAL;
242    }
243    return NETSYS_SUCCESS;
244}
245} // namespace OHOS::NetManagerStandard
246