/* * 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 #include #include #include #include #include struct ByteArrayHash { std::size_t operator()(std::vector 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, 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 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 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 keyVector(map->key_size); memcpy(keyVector.data(), key, map->key_size); std::vector 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 keyVector(map->key_size); memcpy(keyVector.data(), key, map->key_size); byteArrayMap& currentMap = getCurrentMap(map); return currentMap.erase(keyVector); }