1 /* 2 * Copyright 2024, 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 #ifndef APF_INTERPRETER_H_ 18 #define APF_INTERPRETER_H_ 19 20 #include <stdint.h> 21 22 #ifdef __cplusplus 23 extern "C" { 24 #endif 25 26 /** 27 * Returns the max version of the APF instruction set supported by apf_run(). 28 * APFv6 is a superset of APFv4. APFv6 interpreters are able to run APFv4 code. 29 */ 30 uint32_t apf_version(void); 31 32 /** 33 * Allocates a buffer for the APF program to build a reply packet. 34 * 35 * Unless in a critical low memory state, the firmware must allow allocating at 36 * least one 1514 byte buffer for every call to apf_run(). The interpreter will 37 * have at most one active allocation at any given time, and will always either 38 * transmit or deallocate the buffer before apf_run() returns. 39 * 40 * It is OK if the firmware decides to limit allocations to at most one per 41 * apf_run() invocation. This allows the firmware to delay transmitting 42 * the buffer until after apf_run() has returned (by keeping track of whether 43 * a buffer was allocated/deallocated/scheduled for transmit) and may 44 * allow the use of a single statically allocated 1514+ byte buffer. 45 * 46 * The firmware MAY choose to allocate a larger buffer than requested, and 47 * give the apf_interpreter a pointer to the middle of the buffer. This will 48 * allow firmware to later (during or after apf_transmit_buffer call) populate 49 * any required headers, trailers, etc. 50 * 51 * @param ctx - unmodified ctx pointer passed into apf_run(). 52 * @param size - the minimum size of buffer to allocate 53 * @return the pointer to the allocated region. The function can return NULL to 54 * indicate allocation failure, for example if too many buffers are 55 * pending transmit. Returning NULL will most likely result in 56 * apf_run() returning PASS. 57 */ 58 uint8_t* apf_allocate_buffer(void* ctx, uint32_t size); 59 60 /** 61 * Transmits the allocated buffer and deallocates it. 62 * 63 * The apf_interpreter will not read/write from/to the buffer once it calls 64 * this function. 65 * 66 * The content of the buffer between [ptr, ptr + len) are the bytes to be 67 * transmitted, starting from the ethernet header and not including any 68 * ethernet CRC bytes at the end. 69 * 70 * The firmware is expected to make its best effort to transmit. If it 71 * exhausts retries, or if there is no channel for too long and the transmit 72 * queue is full, then it is OK for the packet to be dropped. The firmware should 73 * prefer to fail allocation if it can predict transmit will fail. 74 * 75 * apf_transmit_buffer() may be asynchronous, which means the actual packet 76 * transmission can happen sometime after the function returns. 77 * 78 * @param ctx - unmodified ctx pointer passed into apf_run(). 79 * @param ptr - pointer to the transmit buffer, must have been previously 80 * returned by apf_allocate_buffer() and not deallocated. 81 * @param len - the number of bytes to be transmitted (possibly less than 82 * the allocated buffer), 0 means don't transmit the buffer 83 * but only deallocate it. 84 * @param dscp - value in [0..63] - the upper 6 bits of the TOS field in 85 * the IPv4 header or traffic class field in the IPv6 header. 86 * @return non-zero if the firmware *knows* the transmit will fail, zero if 87 * the transmit succeeded or the firmware thinks it will succeed. 88 * Returning an error will likely result in apf_run() returning PASS. 89 */ 90 int apf_transmit_buffer(void* ctx, uint8_t* ptr, uint32_t len, uint8_t dscp); 91 92 /** 93 * Runs an APF program over a packet. 94 * 95 * The return value of apf_run indicates whether the packet should 96 * be passed or dropped. As a part of apf_run() execution, the APF 97 * program can call apf_allocate_buffer()/apf_transmit_buffer() to construct 98 * a reply packet and transmit it. 99 * 100 * The text section containing the program instructions starts at address 101 * program and stops at + program_len - 1, and the writable data section 102 * begins at program + program_len and ends at program + ram_len - 1, 103 * as described in the following diagram: 104 * 105 * program program + program_len program + ram_len 106 * | text section | data section | 107 * +--------------------+------------------------+ 108 * 109 * @param ctx - pointer to any additional context required for allocation and transmit. 110 * May be NULL if no such context is required. This is opaque to 111 * the interpreter and will be passed through unmodified 112 * to apf_allocate_buffer() and apf_transmit_buffer() calls. 113 * @param program - the program bytecode, followed by the writable data region. 114 * Note: this *MUST* be a 4 byte aligned region. 115 * @param program_len - the length in bytes of the read-only portion of the APF 116 * buffer pointed to by {@code program}. 117 * This is determined by the size of the loaded APF program. 118 * @param ram_len - total length of the APF buffer pointed to by 119 * {@code program}, including the read-only bytecode 120 * portion and the read-write data portion. 121 * This is expected to be a constant which doesn't change 122 * value even when a new APF program is loaded. 123 * Note: this *MUST* be a multiple of 4. 124 * @param packet - the packet bytes, starting from the ethernet header. 125 * @param packet_len - the length of {@code packet} in bytes, not 126 * including trailers/CRC. 127 * @param filter_age_16384ths - the number of 1/16384 seconds since the filter 128 * was programmed. 129 * 130 * @return zero if packet should be dropped, 131 * non-zero if packet should be passed, specifically: 132 * - 1 on normal apf program execution, 133 * - 2 on exceptional circumstances (caused by bad firmware integration), 134 * these include: 135 * - program pointer which is not aligned to 4 bytes 136 * - ram_len which is not a multiple of 4 bytes 137 * - excessively large (>= 2GiB) program_len or ram_len 138 * - packet pointer which is a null pointer 139 * - packet_len shorter than ETH_HLEN (14) 140 * As such, you may want to log a firmware exception if 2 is ever returned... 141 * 142 * 143 * NOTE: How to calculate filter_age_16384ths: 144 * 145 * - if you have a u64 clock source counting nanoseconds: 146 * u64 nanoseconds = current_nanosecond_time_u64() - filter_installation_nanosecond_time_u64; 147 * u32 filter_age_16384ths = (u32)((nanoseconds << 5) / 1953125); 148 * 149 * - if you have a u64 clock source counting microseconds: 150 * u64 microseconds = current_microsecond_time_u64() - filter_installation_microsecond_time_u64; 151 * u32 filter_age_16384ths = (u32)((microseconds << 8) / 15625); 152 * 153 * - if you have a u64 clock source counting milliseconds: 154 * u64 milliseconds = current_millisecond_time_u64() - filter_installation_millisecond_time_u64; 155 * u32 filter_age_16384ths = (u32)((milliseconds << 11) / 125); 156 * 157 * - if you have a u32 clock source counting milliseconds and cannot use 64-bit arithmetic: 158 * u32 milliseconds = current_millisecond_time_u32() - filter_installation_millisecond_time_u32; 159 * u32 filter_age_16384ths = ((((((milliseconds << 4) / 5) << 2) / 5) << 2) / 5) << 3; 160 * or the less precise: 161 * u32 filter_age_16384ths = ((milliseconds << 4) / 125) << 7; 162 * 163 * - if you have a u32 clock source counting seconds: 164 * u32 seconds = current_second_time_u32() - filter_installation_second_time_u32; 165 * u32 filter_age_16384ths = seconds << 14; 166 */ 167 int apf_run(void* ctx, uint32_t* const program, const uint32_t program_len, 168 const uint32_t ram_len, const uint8_t* const packet, 169 const uint32_t packet_len, const uint32_t filter_age_16384ths); 170 171 #ifdef __cplusplus 172 } 173 #endif 174 175 #endif /* APF_INTERPRETER_H_ */ 176