1 /*
2 * Copyright (c) 2024 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 "bpf_ring_buffer.h"
17 #include "net_policy_client.h"
18 #include "libbpf.h"
19 #include "ffrt.h"
20 #include "ffrt_inner.h"
21
22 namespace OHOS::NetManagerStandard {
23 namespace {
24 const int RING_BUFFER_POLL_TIME_OUT_MS = -1;
25 const uint32_t TRAFFIC_CALLBACK_MAX_NUM = 20;
26 }
27 bool NetsysBpfRingBuffer::existThread_ = true;
28 std::atomic_bool NetsysBpfRingBuffer::existNetStatsThread_ = true;
29 std::vector<sptr<NetsysNative::INetsysTrafficCallback>> NetsysBpfRingBuffer::callbacks_ = {};
30 std::mutex NetsysBpfRingBuffer::callbackMutex_;
31
BpfMapPathNameToU64(const std::string & pathName)32 uint64_t NetsysBpfRingBuffer::BpfMapPathNameToU64(const std::string &pathName)
33 {
34 return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pathName.c_str()));
35 }
36
BpfSyscall(int32_t cmd,const bpf_attr & attr)37 int32_t NetsysBpfRingBuffer::BpfSyscall(int32_t cmd, const bpf_attr &attr)
38 {
39 return static_cast<int32_t>(syscall(__NR_bpf, cmd, &attr, sizeof(attr)));
40 }
41
GetRingbufFd(const std::string & path,uint32_t fileFlags)42 int NetsysBpfRingBuffer::GetRingbufFd(const std::string &path, uint32_t fileFlags)
43 {
44 bpf_attr bpfAttr{};
45 memset_s(&bpfAttr, sizeof(bpfAttr), 0, sizeof(bpfAttr));
46 bpfAttr.pathname = BpfMapPathNameToU64(path);
47 bpfAttr.file_flags = fileFlags;
48 return BpfSyscall(BPF_OBJ_GET, bpfAttr);
49 }
50
HandleNetworkPolicyEventCallback(void * ctx,void * data,size_t data_sz)51 int NetsysBpfRingBuffer::HandleNetworkPolicyEventCallback(void *ctx, void *data, size_t data_sz)
52 {
53 NETNATIVE_LOG_D("HandleNetworkPolicyEventCallback enter");
54 if (data == nullptr) {
55 NETNATIVE_LOGE("data error");
56 return RING_BUFFER_ERR_INTERNAL;
57 }
58 int32_t *e = (int32_t*)data;
59
60 if (NetPolicyClient::GetInstance().NotifyNetAccessPolicyDiag(*e) != NETMANAGER_SUCCESS) {
61 NETNATIVE_LOGE("Notify to diag fail");
62 return RING_BUFFER_ERR_INTERNAL;
63 }
64
65 return RING_BUFFER_ERR_NONE;
66 }
67
RegisterNetsysTrafficCallback(const sptr<NetsysNative::INetsysTrafficCallback> & callback)68 int NetsysBpfRingBuffer::RegisterNetsysTrafficCallback(const sptr<NetsysNative::INetsysTrafficCallback> &callback)
69 {
70 NETNATIVE_LOGI("callback is start");
71 std::lock_guard<std::mutex> lock(callbackMutex_);
72
73 if (callbacks_.size() > TRAFFIC_CALLBACK_MAX_NUM) {
74 NETNATIVE_LOGE("callback nums more than 20");
75 return 0;
76 }
77
78 for (const auto &cb : callbacks_) {
79 if (cb == callback) {
80 NETNATIVE_LOGI("callback is already registered");
81 return 0;
82 }
83 }
84 callbacks_.emplace_back(callback);
85 NETNATIVE_LOGI("callback is registered successfully current size is %{public}zu", callbacks_.size());
86 return 0;
87 }
88
UnRegisterNetsysTrafficCallback(const sptr<NetsysNative::INetsysTrafficCallback> & callback)89 int NetsysBpfRingBuffer::UnRegisterNetsysTrafficCallback(const sptr<NetsysNative::INetsysTrafficCallback> &callback)
90 {
91 std::lock_guard<std::mutex> lock(callbackMutex_);
92
93 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
94 if (*it == callback) {
95 callbacks_.erase(it);
96 NETNATIVE_LOGI("callback is unregistered successfully");
97 return 0;
98 }
99 }
100 NETNATIVE_LOGI("callback has not registered current callback number is %{public}zu", callbacks_.size());
101 return -1;
102 }
103
HandleNetStatsEventCallback(void * ctx,void * data,size_t dataSz)104 int NetsysBpfRingBuffer::HandleNetStatsEventCallback(void *ctx, void *data, size_t dataSz)
105 {
106 NETNATIVE_LOGI("HandleNetStatsEventCallback enter");
107 if (data == nullptr || dataSz == 0) {
108 NETNATIVE_LOGE("data error");
109 return RING_BUFFER_ERR_INTERNAL;
110 }
111 int8_t *value = reinterpret_cast<int8_t *>(data);
112
113 std::lock_guard<std::mutex> lock(callbackMutex_);
114 for (const auto &callback : callbacks_) {
115 if (callback != nullptr && callback->AsObject() != nullptr && callback->AsObject().GetRefPtr() != nullptr) {
116 NETNATIVE_LOGI("HandleNetStatsEventCallback start. value:%{public}d", *value);
117 callback->OnExceedTrafficLimits(*value);
118 }
119 }
120 return RING_BUFFER_ERR_NONE;
121 }
122
ListenNetStatsRingBufferThread()123 void NetsysBpfRingBuffer::ListenNetStatsRingBufferThread()
124 {
125 NETNATIVE_LOGI("(netstats)ListenNetStatsRingBufferThread start");
126 auto ringbufFd = GetRingbufFd(NET_STATS_RING_BUFFER_MAP_PATH, 0);
127 if (ringbufFd > 0) {
128 /* Set up ring buffer polling */
129 auto rb = ring_buffer__new(ringbufFd, HandleNetStatsEventCallback, NULL, NULL);
130 if (!rb) {
131 NETNATIVE_LOGE("(netstats)Bpf ring buffer new fail");
132 return;
133 }
134
135 /* Process events */
136 while (existNetStatsThread_) {
137 ffrt::sync_io(ringbufFd);
138 int res = ring_buffer__poll(rb, RING_BUFFER_POLL_TIME_OUT_MS);
139 if (res < 0 && errno != EINTR) {
140 NETNATIVE_LOGE("(netstats)Bpf ring buffer poll fail, res: %{public}d, errno: %{public}d", res, errno);
141 break;
142 }
143 }
144
145 ring_buffer__free(rb);
146 }
147
148 NETNATIVE_LOGE("(netstats)Could not get bpf ring buffer map");
149 return;
150 }
151
ListenRingBufferThread(void)152 void NetsysBpfRingBuffer::ListenRingBufferThread(void)
153 {
154 auto ringbufFd = GetRingbufFd(RING_BUFFER_MAP_PATH, 0);
155 if (ringbufFd > 0) {
156 struct ring_buffer *rb = NULL;
157 int err = 0;
158 /* Set up ring buffer polling */
159 rb = ring_buffer__new(ringbufFd, HandleNetworkPolicyEventCallback, NULL, NULL);
160 if (!rb) {
161 err = -1;
162 NETNATIVE_LOGE("Bpf ring buffer new fail");
163 return;
164 }
165
166 /* Process events */
167 while (existThread_) {
168 ffrt::sync_io(ringbufFd);
169 err = ring_buffer__poll(rb, RING_BUFFER_POLL_TIME_OUT_MS);
170 if (err < 0) {
171 NETNATIVE_LOGE("Bpf ring buffer poll fail, err: %{public}d, errno: %{public}d", err, errno);
172 break;
173 }
174 }
175
176 ring_buffer__free(rb);
177 }
178
179 NETNATIVE_LOGE("Could not get bpf ring buffer map");
180 return;
181 }
182
ListenNetworkAccessPolicyEvent(void)183 void NetsysBpfRingBuffer::ListenNetworkAccessPolicyEvent(void)
184 {
185 ffrt::submit(ListenRingBufferThread, {}, {}, ffrt::task_attr().name("ListenRingBufferThread"));
186 }
187
ExistRingBufferPoll(void)188 void NetsysBpfRingBuffer::ExistRingBufferPoll(void)
189 {
190 existThread_ = false;
191 }
192
ListenNetworkStatsEvent(void)193 void NetsysBpfRingBuffer::ListenNetworkStatsEvent(void)
194 {
195 ffrt::submit(ListenNetStatsRingBufferThread, {}, {}, ffrt::task_attr().name("ListenNetStatsRingBufferThread"));
196 }
197
ExistNetstatsRingBufferPoll()198 void NetsysBpfRingBuffer::ExistNetstatsRingBufferPoll()
199 {
200 existNetStatsThread_ = false;
201 }
202 }
203