1 /* 2 * Copyright (C) 2022 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 package com.android.net.module.util; 17 18 import android.system.ErrnoException; 19 20 import androidx.annotation.NonNull; 21 import androidx.annotation.Nullable; 22 23 import java.io.IOException; 24 import java.util.NoSuchElementException; 25 26 /** 27 * The interface of BpfMap. This could be used to inject for testing. 28 * So the testing code won't load the JNI and update the entries to kernel. 29 * 30 * @param <K> the key of the map. 31 * @param <V> the value of the map. 32 */ 33 public interface IBpfMap<K extends Struct, V extends Struct> extends AutoCloseable { 34 /** Update an existing or create a new key -> value entry in an eBbpf map. */ updateEntry(K key, V value)35 void updateEntry(K key, V value) throws ErrnoException; 36 37 /** If the key does not exist in the map, insert key -> value entry into eBpf map. */ insertEntry(K key, V value)38 void insertEntry(K key, V value) throws ErrnoException, IllegalStateException; 39 40 /** If the key already exists in the map, replace its value. */ replaceEntry(K key, V value)41 void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException; 42 43 /** 44 * Update an existing or create a new key -> value entry in an eBbpf map. Returns true if 45 * inserted, false if replaced. (use updateEntry() if you don't care whether insert or replace 46 * happened). 47 */ insertOrReplaceEntry(K key, V value)48 boolean insertOrReplaceEntry(K key, V value) throws ErrnoException; 49 50 /** Remove existing key from eBpf map. Return true if something was deleted. */ deleteEntry(K key)51 boolean deleteEntry(K key) throws ErrnoException; 52 53 /** Get the key after the passed-in key. */ getNextKey(@onNull K key)54 K getNextKey(@NonNull K key) throws ErrnoException; 55 56 /** Get the first key of the eBpf map. */ getFirstKey()57 K getFirstKey() throws ErrnoException; 58 59 /** Returns {@code true} if this map contains no elements. */ isEmpty()60 default boolean isEmpty() throws ErrnoException { 61 return getFirstKey() == null; 62 } 63 64 /** Check whether a key exists in the map. */ containsKey(@onNull K key)65 boolean containsKey(@NonNull K key) throws ErrnoException; 66 67 /** Retrieve a value from the map. */ getValue(@onNull K key)68 V getValue(@NonNull K key) throws ErrnoException; 69 70 public interface ThrowingBiConsumer<T,U> { accept(T t, U u)71 void accept(T t, U u) throws ErrnoException; 72 } 73 74 /** 75 * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. 76 * The given BiConsumer may to delete the passed-in entry, but is not allowed to perform any 77 * other structural modifications to the map, such as adding entries or deleting other entries. 78 * Otherwise, iteration will result in undefined behaviour. 79 */ forEach(ThrowingBiConsumer<K, V> action)80 default public void forEach(ThrowingBiConsumer<K, V> action) throws ErrnoException { 81 @Nullable K nextKey = getFirstKey(); 82 83 while (nextKey != null) { 84 @NonNull final K curKey = nextKey; 85 @NonNull final V value = getValue(curKey); 86 87 nextKey = getNextKey(curKey); 88 action.accept(curKey, value); 89 } 90 } 91 92 /** 93 * Clears the map. The map may already be empty. 94 * 95 * @throws ErrnoException if the map is already closed, if an error occurred during iteration, 96 * or if a non-ENOENT error occurred when deleting a key. 97 */ clear()98 default public void clear() throws ErrnoException { 99 K key = getFirstKey(); 100 while (key != null) { 101 deleteEntry(key); // ignores ENOENT. 102 key = getFirstKey(); 103 } 104 } 105 106 /** Close for AutoCloseable. */ 107 @Override close()108 default void close() throws IOException { 109 }; 110 } 111