1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <inttypes.h>
18 #include <linux/bpf.h>
19 #include <test/mock_bpf_helpers.h>
20 #include <map>
21 #include <unordered_map>
22 #include <vector>
23 
24 struct ByteArrayHash {
operator ()ByteArrayHash25     std::size_t operator()(std::vector<uint8_t> const& bytes) const {
26         size_t result = 0;
27         for (size_t i = 0; i < bytes.size(); i++) {
28             result = (result * 31) ^ bytes[i];
29         }
30         return result;
31     }
32 };
33 
34 typedef std::unordered_map<std::vector<uint8_t>, std::vector<uint8_t>, ByteArrayHash> byteArrayMap;
35 
36 struct mock_bpf_map {
37     uint32_t type;
38     size_t key_size;
39     size_t value_size;
40 
41     // Per-CPU hash map.  Cross-CPU maps have just one key-value pair, the key being 0.
42     std::map<uint32_t, byteArrayMap> map;
43 };
44 
45 static uint64_t gKtimeNs;
46 static uint32_t gSmpProcessorId;
47 static uint32_t gUid;
48 static uint32_t gPidTgid;
49 
bpf_ktime_get_ns()50 uint64_t bpf_ktime_get_ns() {
51     return gKtimeNs;
52 }
53 
mock_bpf_set_ktime_ns(uint64_t time_ns)54 void mock_bpf_set_ktime_ns(uint64_t time_ns) {
55     gKtimeNs = time_ns;
56 }
57 
mock_bpf_set_smp_processor_id(uint32_t cpu)58 void mock_bpf_set_smp_processor_id(uint32_t cpu) {
59     gSmpProcessorId = cpu;
60 }
61 
bpf_get_smp_processor_id()62 uint64_t bpf_get_smp_processor_id() {
63     return gSmpProcessorId;
64 }
65 
mock_bpf_set_current_uid_gid(uint32_t uid)66 void mock_bpf_set_current_uid_gid(uint32_t uid) {
67     gUid = uid;
68 }
69 
bpf_get_current_uid_gid()70 uint64_t bpf_get_current_uid_gid() {
71     return gUid;
72 }
73 
mock_bpf_set_current_pid_tgid(uint64_t pid_tgid)74 void mock_bpf_set_current_pid_tgid(uint64_t pid_tgid) {
75     gPidTgid = pid_tgid;
76 }
77 
bpf_get_current_pid_tgid()78 uint64_t bpf_get_current_pid_tgid() {
79     return gPidTgid;
80 }
81 
mock_bpf_map_create(uint32_t key_size,uint32_t value_size,uint32_t type)82 mock_bpf_map_t mock_bpf_map_create(uint32_t key_size, uint32_t value_size, uint32_t type) {
83     mock_bpf_map* map = new mock_bpf_map();
84     map->type = type;
85     map->key_size = key_size;
86     map->value_size = value_size;
87     return map;
88 }
89 
getCurrentMap(mock_bpf_map * map)90 static byteArrayMap& getCurrentMap(mock_bpf_map* map) {
91     if (map->type == BPF_MAP_TYPE_PERCPU_HASH || map->type == BPF_MAP_TYPE_PERCPU_ARRAY) {
92         return map->map[gSmpProcessorId];
93     } else {
94         return map->map[0];
95     }
96 }
97 
mock_bpf_lookup_elem(mock_bpf_map_t mock_map,void * key)98 void* mock_bpf_lookup_elem(mock_bpf_map_t mock_map, void* key) {
99     mock_bpf_map* map = (mock_bpf_map*)mock_map;
100     std::vector<uint8_t> keyVector(map->key_size);
101     memcpy(keyVector.data(), key, map->key_size);
102     byteArrayMap& currentMap = getCurrentMap(map);
103     if (currentMap.find(keyVector) == currentMap.end()) {
104         return NULL;
105     }
106     return currentMap[keyVector].data();
107 }
108 
mock_bpf_update_elem(mock_bpf_map_t mock_map,void * key,void * value,uint64_t flags)109 int mock_bpf_update_elem(mock_bpf_map_t mock_map, void* key, void* value, uint64_t flags) {
110     mock_bpf_map* map = (mock_bpf_map*)mock_map;
111     std::vector<uint8_t> keyVector(map->key_size);
112     memcpy(keyVector.data(), key, map->key_size);
113     std::vector<uint8_t> value_vector(map->value_size);
114     memcpy(value_vector.data(), value, map->value_size);
115 
116     byteArrayMap& currentMap = getCurrentMap(map);
117     if (flags & BPF_EXIST) {
118         if (currentMap.find(keyVector) == currentMap.end()) {
119             return 0;
120         }
121     } else if (flags & BPF_NOEXIST) {
122         if (currentMap.find(keyVector) != currentMap.end()) {
123             return 0;
124         }
125     }
126     currentMap[keyVector] = value_vector;
127     return 1;
128 }
129 
mock_bpf_delete_elem(mock_bpf_map_t mock_map,void * key)130 int mock_bpf_delete_elem(mock_bpf_map_t mock_map, void* key) {
131     mock_bpf_map* map = (mock_bpf_map*)mock_map;
132     std::vector<uint8_t> keyVector(map->key_size);
133     memcpy(keyVector.data(), key, map->key_size);
134 
135     byteArrayMap& currentMap = getCurrentMap(map);
136     return currentMap.erase(keyVector);
137 }
138