blob: 1197377bc05901d62d27baec16de8ef45f1f8bf9 [file] [log] [blame]
/*
* Copyright (C) 2021 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 <inttypes.h>
#include <linux/bpf.h>
#include <test/mock_bpf_helpers.h>
#include <map>
#include <unordered_map>
#include <vector>
struct ByteArrayHash {
std::size_t operator()(std::vector<uint8_t> const& bytes) const {
size_t result = 0;
for (size_t i = 0; i < bytes.size(); i++) {
result = (result * 31) ^ bytes[i];
}
return result;
}
};
typedef std::unordered_map<std::vector<uint8_t>, std::vector<uint8_t>, ByteArrayHash> byteArrayMap;
struct mock_bpf_map {
uint32_t type;
size_t key_size;
size_t value_size;
// Per-CPU hash map. Cross-CPU maps have just one key-value pair, the key being 0.
std::map<uint32_t, byteArrayMap> map;
};
static uint64_t gKtimeNs;
static uint32_t gSmpProcessorId;
static uint32_t gUid;
static uint32_t gPidTgid;
uint64_t bpf_ktime_get_ns() {
return gKtimeNs;
}
void mock_bpf_set_ktime_ns(uint64_t time_ns) {
gKtimeNs = time_ns;
}
void mock_bpf_set_smp_processor_id(uint32_t cpu) {
gSmpProcessorId = cpu;
}
uint64_t bpf_get_smp_processor_id() {
return gSmpProcessorId;
}
void mock_bpf_set_current_uid_gid(uint32_t uid) {
gUid = uid;
}
uint64_t bpf_get_current_uid_gid() {
return gUid;
}
void mock_bpf_set_current_pid_tgid(uint64_t pid_tgid) {
gPidTgid = pid_tgid;
}
uint64_t bpf_get_current_pid_tgid() {
return gPidTgid;
}
mock_bpf_map_t mock_bpf_map_create(uint32_t key_size, uint32_t value_size, uint32_t type) {
mock_bpf_map* map = new mock_bpf_map();
map->type = type;
map->key_size = key_size;
map->value_size = value_size;
return map;
}
static byteArrayMap& getCurrentMap(mock_bpf_map* map) {
if (map->type == BPF_MAP_TYPE_PERCPU_HASH || map->type == BPF_MAP_TYPE_PERCPU_ARRAY) {
return map->map[gSmpProcessorId];
} else {
return map->map[0];
}
}
void* mock_bpf_lookup_elem(mock_bpf_map_t mock_map, void* key) {
mock_bpf_map* map = (mock_bpf_map*)mock_map;
std::vector<uint8_t> keyVector(map->key_size);
memcpy(keyVector.data(), key, map->key_size);
byteArrayMap& currentMap = getCurrentMap(map);
if (currentMap.find(keyVector) == currentMap.end()) {
return NULL;
}
return currentMap[keyVector].data();
}
int mock_bpf_update_elem(mock_bpf_map_t mock_map, void* key, void* value, uint64_t flags) {
mock_bpf_map* map = (mock_bpf_map*)mock_map;
std::vector<uint8_t> keyVector(map->key_size);
memcpy(keyVector.data(), key, map->key_size);
std::vector<uint8_t> value_vector(map->value_size);
memcpy(value_vector.data(), value, map->value_size);
byteArrayMap& currentMap = getCurrentMap(map);
if (flags & BPF_EXIST) {
if (currentMap.find(keyVector) == currentMap.end()) {
return 0;
}
} else if (flags & BPF_NOEXIST) {
if (currentMap.find(keyVector) != currentMap.end()) {
return 0;
}
}
currentMap[keyVector] = value_vector;
return 1;
}
int mock_bpf_delete_elem(mock_bpf_map_t mock_map, void* key) {
mock_bpf_map* map = (mock_bpf_map*)mock_map;
std::vector<uint8_t> keyVector(map->key_size);
memcpy(keyVector.data(), key, map->key_size);
byteArrayMap& currentMap = getCurrentMap(map);
return currentMap.erase(keyVector);
}