• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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