• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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