/src/openvswitch/lib/dpif-offload-provider.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2025 Red Hat, Inc. |
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 DPIF_OFFLOAD_PROVIDER_H |
18 | | #define DPIF_OFFLOAD_PROVIDER_H |
19 | | |
20 | | #include "cmap.h" |
21 | | #include "dpif-offload.h" |
22 | | #include "dpif-provider.h" |
23 | | #include "ovs-thread.h" |
24 | | #include "smap.h" |
25 | | #include "util.h" |
26 | | |
27 | | #include "openvswitch/list.h" |
28 | | |
29 | | /* The DPIF Offload Provider introduces an abstraction layer for hardware |
30 | | * offload functionality implemented at the netdevice level. It sits above |
31 | | * the netdevice layer within the DPIF (Datapath Interface) framework, |
32 | | * providing a standardized API for offloading packet processing tasks to |
33 | | * hardware-accelerated datapaths. |
34 | | * |
35 | | * By decoupling hardware-specific implementations from the core DPIF layer, |
36 | | * this abstraction enables greater flexibility, maintainability, and support |
37 | | * for multiple hardware offload mechanisms without directly modifying DPIF |
38 | | * internals. */ |
39 | | |
40 | | /* DPIF Offload specific structure pointed to in struct dpif. */ |
41 | | struct dpif_offload_provider_collection { |
42 | | char *dpif_name; /* Name of the associated dpif. */ |
43 | | |
44 | | struct ovs_list list; /* Note that offload providers will only be added |
45 | | * at dpif creation time and removed during |
46 | | * destruction. No intermediate additions or |
47 | | * deletions are allowed; hence no locking of the |
48 | | * list is required. */ |
49 | | |
50 | | struct ovs_mutex mutex; /* Mutex to protect all below. */ |
51 | | struct ovs_refcount ref_cnt; |
52 | | }; |
53 | | |
54 | | /* This structure should be treated as opaque by dpif offload implementations. |
55 | | */ |
56 | | struct dpif_offload { |
57 | | const struct dpif_offload_class *class; |
58 | | struct ovs_list dpif_list_node; |
59 | | char *name; |
60 | | }; |
61 | | |
62 | | |
63 | | struct dpif_offload_flow_dump { |
64 | | struct dpif_offload *offload; |
65 | | bool terse; |
66 | | }; |
67 | | |
68 | | static inline void |
69 | | dpif_offload_flow_dump_init(struct dpif_offload_flow_dump *dump, |
70 | | const struct dpif_offload *offload, bool terse) |
71 | 0 | { |
72 | 0 | dump->offload = CONST_CAST(struct dpif_offload *, offload); |
73 | 0 | dump->terse = terse; |
74 | 0 | } Unexecuted instantiation: dpif-offload.c:dpif_offload_flow_dump_init Unexecuted instantiation: dpif-offload-dummy.c:dpif_offload_flow_dump_init Unexecuted instantiation: dpif.c:dpif_offload_flow_dump_init Unexecuted instantiation: dpif-offload-tc.c:dpif_offload_flow_dump_init |
75 | | |
76 | | struct dpif_offload_flow_dump_thread { |
77 | | struct dpif_offload_flow_dump *dump; |
78 | | }; |
79 | | |
80 | | static inline void |
81 | | dpif_offload_flow_dump_thread_init( |
82 | | struct dpif_offload_flow_dump_thread *thread, |
83 | | struct dpif_offload_flow_dump *dump) |
84 | 0 | { |
85 | 0 | thread->dump = dump; |
86 | 0 | } Unexecuted instantiation: dpif-offload.c:dpif_offload_flow_dump_thread_init Unexecuted instantiation: dpif-offload-dummy.c:dpif_offload_flow_dump_thread_init Unexecuted instantiation: dpif.c:dpif_offload_flow_dump_thread_init Unexecuted instantiation: dpif-offload-tc.c:dpif_offload_flow_dump_thread_init |
87 | | |
88 | | |
89 | | struct dpif_offload_class { |
90 | | /* Type of DPIF offload provider in this class, e.g., "tc", "dpdk", |
91 | | * "dummy", etc. */ |
92 | | const char *type; |
93 | | |
94 | | /* List of DPIF implementation types supported by the offload provider. |
95 | | * This is implemented as a pointer to a null-terminated list of const |
96 | | * type strings. For more details on these type strings, see the |
97 | | * 'struct dpif_class' definition. */ |
98 | | const char *const *supported_dpif_types; |
99 | | |
100 | | /* Type of flow implementation for this DPIF offload provider. */ |
101 | | enum dpif_offload_impl_type impl_type; |
102 | | |
103 | | /* Called when the dpif offload provider class is registered. Note that |
104 | | * this is the global initialization, not the per dpif one. */ |
105 | | int (*init)(void); |
106 | | |
107 | | /* Attempts to open the offload provider for the specified dpif. |
108 | | * If successful, stores a pointer to the new dpif offload in |
109 | | * 'dpif_offload **', which must be of class 'dpif_offload_class'. |
110 | | * On failure (indicated by a negative return value), there are no |
111 | | * requirements for what is stored in 'dpif_offload **'. */ |
112 | | int (*open)(const struct dpif_offload_class *, |
113 | | struct dpif *, struct dpif_offload **); |
114 | | |
115 | | /* Closes 'dpif_offload' and frees associated memory and resources. |
116 | | * This includes freeing the 'dpif_offload' structure allocated by |
117 | | * open() above. If implementation accesses this provider using |
118 | | * RCU pointers, it's responsible for handling deferred deallocation. */ |
119 | | void (*close)(struct dpif_offload *); |
120 | | /* Pass custom configuration options to the offload provider. */ |
121 | | void (*set_config)(struct dpif_offload *, |
122 | | const struct smap *other_config); |
123 | | |
124 | | /* Retrieve debug information from the offload provider in either string |
125 | | * (ds) or JSON format. If both formats are requested, the provider may |
126 | | * choose which one to return. Note that the actual format is unspecified, |
127 | | * it's up to the provider to decide what to return. If 'ds' is supplied, |
128 | | * it should be initialized, and might already contain data. The caller is |
129 | | * responsible for freeing any returned 'ds' or 'json' pointers. */ |
130 | | void (*get_debug)(const struct dpif_offload *offload, struct ds *ds, |
131 | | struct json *json); |
132 | | |
133 | | /* Get hardware offload activity counters from the data plane. |
134 | | * These counters are not interface offload statistics, but rather a status |
135 | | * report of hardware offload management: how many offloads are currently |
136 | | * waiting, inserted, etc. If this function returns an error, the 'stats' |
137 | | * structure should not be touched, that is, it remains uninitialized. */ |
138 | | int (*get_global_stats)(const struct dpif_offload *offload, |
139 | | struct netdev_custom_stats *stats); |
140 | | |
141 | | /* Verifies whether the offload provider supports offloading flows for the |
142 | | * given 'netdev'. Returns 'false' if the provider lacks the capabilities |
143 | | * to offload on this port, otherwise returns 'true'. */ |
144 | | bool (*can_offload)(struct dpif_offload *, |
145 | | struct netdev *); |
146 | | |
147 | | /* This callback is invoked when a 'netdev' port has been successfully |
148 | | * added to the dpif and should be handled by this offload provider. |
149 | | * It is assumed that the 'can_offload' callback was previously called |
150 | | * and returned 'true' before this function is executed. */ |
151 | | int (*port_add)(struct dpif_offload *, struct netdev *, |
152 | | odp_port_t port_no); |
153 | | |
154 | | /* This callback is invoked when the 'port_no' port has been successfully |
155 | | * removed from the dpif. Note that it is called for every deleted port, |
156 | | * even if 'port_added' was never called, as the framework does not track |
157 | | * added ports. */ |
158 | | int (*port_del)(struct dpif_offload *, odp_port_t port_no); |
159 | | |
160 | | /* Refreshes the configuration of 'port_no' port. The same note as above |
161 | | * in 'port_deleted' applies here. */ |
162 | | void (*port_set_config)(struct dpif_offload *, odp_port_t port_no, |
163 | | const struct smap *cfg); |
164 | | |
165 | | /* Attempts to begin dumping the ports in a dpif_offload. On success, |
166 | | * returns 0 and initializes '*statep' with any data needed for iteration. |
167 | | * On failure, returns a positive errno value. */ |
168 | | int (*port_dump_start)(const struct dpif_offload *, void **statep); |
169 | | |
170 | | /* Attempts to retrieve another port from 'dpif_offload' for 'state', which |
171 | | * was initialized by a successful call to the 'port_dump_start' function |
172 | | * for 'dpif_offload'. On success, stores a new dpif_offload_port into |
173 | | * 'port' and returns 0. Returns EOF if the end of the port table has been |
174 | | * reached, or a positive errno value on error. This function will not be |
175 | | * called again once it returns nonzero once for a given iteration (but |
176 | | * the 'port_dump_done' function will be called afterward). |
177 | | * |
178 | | * The dpif provider retains ownership of the data stored in 'port'. It |
179 | | * must remain valid until at least the next call to 'port_dump_next' or |
180 | | * 'port_dump_done' for 'state'. */ |
181 | | int (*port_dump_next)(const struct dpif_offload *, void *state, |
182 | | struct dpif_offload_port *); |
183 | | |
184 | | /* Releases resources from 'dpif_offload' for 'state', which was |
185 | | * initialized by a successful call to the 'port_dump_start' function for |
186 | | * 'dpif_offload'. */ |
187 | | int (*port_dump_done)(const struct dpif_offload *dpif, void *state); |
188 | | |
189 | | /* Deletes all offloaded flows for this offload_provider. Return 0 if |
190 | | * successful, otherwise returns a positive errno value. */ |
191 | | int (*flow_flush)(const struct dpif_offload *); |
192 | | |
193 | | /* Flow Dumping Interface for dpif-offload. |
194 | | * |
195 | | * This interface mirrors the flow dumping interface found in the dpif |
196 | | * layer. For a thorough understanding of the design and expectations, |
197 | | * please refer to the documentation in: |
198 | | * - include/openvswitch/dpif.h |
199 | | * - include/openvswitch/dpif-provider.h |
200 | | * |
201 | | * The dpif-offload flow dumping interface is intended for use only when |
202 | | * there is a clear separation between traditional dpif flows and offloaded |
203 | | * flows handled by an offload mechanism. |
204 | | * |
205 | | * For example: |
206 | | * - The 'tc' offload provider installs flow rules via kernel tc without |
207 | | * creating corresponding kernel datapath (dpif) flows. In such cases, |
208 | | * dumping dpif flows would not reflect the actual set of active |
209 | | * offloaded flows. This interface provides a way to explicitly |
210 | | * enumerate such offloaded flows. |
211 | | * |
212 | | * 'flow_dump_create' and 'flow_dump_thread_create' must always return |
213 | | * initialized and usable data structures. Specifically, they must |
214 | | * initialize the returned structures using dpif_offload_flow_dump_init() |
215 | | * and dpif_offload_flow_dump_thread_init(), respectively, and defer any |
216 | | * error reporting until flow_dump_destroy() is called. */ |
217 | | struct dpif_offload_flow_dump *(*flow_dump_create)( |
218 | | const struct dpif_offload *, bool terse); |
219 | | |
220 | | int (*flow_dump_next)(struct dpif_offload_flow_dump_thread *, |
221 | | struct dpif_flow *, int max_flows); |
222 | | |
223 | | int (*flow_dump_destroy)(struct dpif_offload_flow_dump *); |
224 | | |
225 | | struct dpif_offload_flow_dump_thread *(*flow_dump_thread_create)( |
226 | | struct dpif_offload_flow_dump *); |
227 | | |
228 | | void (*flow_dump_thread_destroy)(struct dpif_offload_flow_dump_thread *); |
229 | | |
230 | | /* Executes each of the 'n_ops' operations in 'ops' in order if their |
231 | | * 'error' field is negative, placing each operation's results in the |
232 | | * 'output' members documented in comments and the 'error' member of each |
233 | | * dpif_op. Operations with a non-negative 'error' value have already been |
234 | | * processed by a higher priority offload provider. |
235 | | * |
236 | | * Note that only the DPIF_OP_FLOW_PUT/DEL/GET operations should be |
237 | | * handled, and this is only needed for the |
238 | | * DPIF_OFFLOAD_IMPL_FLOWS_PROVIDER_ONLY type of offload providers. */ |
239 | | void (*operate)(struct dpif *, const struct dpif_offload *, |
240 | | struct dpif_op **, size_t n_ops); |
241 | | |
242 | | /* Returns the number of flows offloaded by the offload provider. */ |
243 | | uint64_t (*flow_count)(const struct dpif_offload *); |
244 | | |
245 | | /* Adds or modifies the meter in 'dpif_offload' with the given 'meter_id' |
246 | | * and the configuration in 'config'. |
247 | | * |
248 | | * The meter id specified through 'config->meter_id' is ignored. */ |
249 | | int (*meter_set)(const struct dpif_offload *, ofproto_meter_id meter_id, |
250 | | struct ofputil_meter_config *); |
251 | | |
252 | | /* Queries HW for meter stats with the given 'meter_id'. Store the stats |
253 | | * of dropped packets to band 0. On failure, a non-zero error code is |
254 | | * returned. |
255 | | * |
256 | | * Note that the 'stats' structure is already initialized, and only the |
257 | | * available statistics should be incremented, not replaced. Those fields |
258 | | * are packet_in_count, byte_in_count and band[]->byte_count and |
259 | | * band[]->packet_count. */ |
260 | | int (*meter_get)(const struct dpif_offload *, ofproto_meter_id meter_id, |
261 | | struct ofputil_meter_stats *); |
262 | | |
263 | | /* Removes meter 'meter_id' from HW. Store the stats of dropped packets to |
264 | | * band 0. On failure, a non-zero error code is returned. |
265 | | * |
266 | | * 'stats' may be passed in as NULL if no stats are needed. See the above |
267 | | * function for additional details on the 'stats' usage. */ |
268 | | int (*meter_del)(const struct dpif_offload *, ofproto_meter_id meter_id, |
269 | | struct ofputil_meter_stats *); |
270 | | |
271 | | /* Return the 'netdev' associated with the port_no if this offload |
272 | | * provider is handling offload for this port/netdev. The returned |
273 | | * netdev is owned by the port manager and its reference count is |
274 | | * NOT incremented. Callers needing to hold a reference must call |
275 | | * netdev_ref() on the returned netdev. Returns NULL if port_no is |
276 | | * not found. */ |
277 | | struct netdev *(*get_netdev)(struct dpif_offload *, odp_port_t port_no); |
278 | | |
279 | | |
280 | | /* These APIs operate directly on the provided netdev for performance |
281 | | * reasons. They are intended for use in fast path processing and should |
282 | | * be designed with speed and efficiency in mind. */ |
283 | | |
284 | | /* Recover and/or set the packet state (contents and metadata) for |
285 | | * continued processing in software, and/or perform any additional |
286 | | * post-processing required by the offload provider. |
287 | | * |
288 | | * Return 0 if successful and the packet requires further processing; |
289 | | * otherwise, return a positive errno value and take ownership of the |
290 | | * packet if errno != EOPNOTSUPP. Return ECANCELED if the packet was |
291 | | * fully consumed by the provider for non-error conditions. |
292 | | * |
293 | | * When zero (0) is returned, the 'flow_reference' pointer may reference |
294 | | * the flow_reference passed to the matching flow. This can be used to |
295 | | * support partial offloads. The returned pointer must remain valid until |
296 | | * the end of the next RCU grace period. */ |
297 | | int (*netdev_hw_post_process)(const struct dpif_offload *, struct netdev *, |
298 | | unsigned pmd_id, struct dp_packet *, |
299 | | void **flow_reference); |
300 | | |
301 | | /* Add or modify the specified flow directly in the offload datapath. |
302 | | * The actual implementation may choose to handle the offload |
303 | | * asynchronously by returning EINPROGRESS and invoking the supplied |
304 | | * 'callback' once completed. If the flow is handled asynchronously, the |
305 | | * order should be guaranteed. For successful synchronous handling, the |
306 | | * callback must not be called, and 0 should be returned. If this call is |
307 | | * not successful, a positive errno value should be returned. */ |
308 | | int (*netdev_flow_put)(const struct dpif_offload *, struct netdev *, |
309 | | struct dpif_offload_flow_put *, |
310 | | void **previous_flow_reference); |
311 | | |
312 | | /* Delete the specified flow directly from the offloaded datapath. See the |
313 | | * above 'netdev_flow_put' for implementation details. */ |
314 | | int (*netdev_flow_del)(const struct dpif_offload *, struct netdev *, |
315 | | struct dpif_offload_flow_del *); |
316 | | |
317 | | /* Get offload statistics based on the flows 'ufid'. Note that this API |
318 | | * does NOT support asynchronous handling. Returns 'true' if the flow was |
319 | | * offloaded, 'false' if not. In the latter case, 'stats' and 'attrs' |
320 | | * are not valid. */ |
321 | | bool (*netdev_flow_stats)(const struct dpif_offload *, struct netdev *, |
322 | | const ovs_u128 *ufid, |
323 | | struct dpif_flow_stats *stats, |
324 | | struct dpif_flow_attrs *attrs); |
325 | | |
326 | | /* Registers a callback that is invoked when a flow reference is released |
327 | | * by the offload provider, i.e., when the flow reference previously passed |
328 | | * to netdev_flow_put() is no longer held by the offload provider. */ |
329 | | void (*register_flow_unreference_cb)(const struct dpif_offload *, |
330 | | dpif_offload_flow_unreference_cb *); |
331 | | }; |
332 | | |
333 | | extern struct dpif_offload_class dpif_offload_dummy_class; |
334 | | extern struct dpif_offload_class dpif_offload_dummy_x_class; |
335 | | extern struct dpif_offload_class dpif_offload_dpdk_class; |
336 | | extern struct dpif_offload_class dpif_offload_tc_class; |
337 | | |
338 | | |
339 | | /* Structure used by the common dpif port management library functions. */ |
340 | | struct dpif_offload_port_mgr { |
341 | | struct ovs_mutex cmap_mod_lock; |
342 | | |
343 | | struct cmap odp_port_to_port; |
344 | | struct cmap netdev_to_port; |
345 | | struct cmap ifindex_to_port; |
346 | | }; |
347 | | |
348 | | struct dpif_offload_port_mgr_port { |
349 | | struct cmap_node odp_port_node; |
350 | | struct cmap_node netdev_node; |
351 | | struct cmap_node ifindex_node; |
352 | | struct netdev *netdev; |
353 | | odp_port_t port_no; |
354 | | int ifindex; |
355 | | }; |
356 | | |
357 | | |
358 | | /* Global dpif port management library functions. */ |
359 | | struct dpif_offload_port_mgr *dpif_offload_port_mgr_init(void); |
360 | | bool dpif_offload_port_mgr_add(struct dpif_offload_port_mgr *, |
361 | | struct dpif_offload_port_mgr_port *, |
362 | | struct netdev *netdev, odp_port_t, |
363 | | bool need_ifindex); |
364 | | struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_remove( |
365 | | struct dpif_offload_port_mgr *, odp_port_t); |
366 | | void dpif_offload_port_mgr_uninit(struct dpif_offload_port_mgr *); |
367 | | size_t dpif_offload_port_mgr_port_count(struct dpif_offload_port_mgr *); |
368 | | struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_ifindex( |
369 | | struct dpif_offload_port_mgr *, int ifindex); |
370 | | struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_netdev( |
371 | | struct dpif_offload_port_mgr *, struct netdev *); |
372 | | struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_odp_port( |
373 | | struct dpif_offload_port_mgr *, odp_port_t); |
374 | | int dpif_offload_port_mgr_port_dump_start(struct dpif_offload_port_mgr *, |
375 | | void **statep); |
376 | | int dpif_offload_port_mgr_port_dump_next(struct dpif_offload_port_mgr *, |
377 | | void *state, |
378 | | struct dpif_offload_port *); |
379 | | int dpif_offload_port_mgr_port_dump_done(struct dpif_offload_port_mgr *, |
380 | | void *state); |
381 | | |
382 | | #define DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH(PORT, PORT_MGR) \ |
383 | 0 | CMAP_FOR_EACH (PORT, odp_port_node, &(PORT_MGR)->odp_port_to_port) |
384 | | |
385 | | /* Global functions, called by the dpif layer or offload providers. */ |
386 | | void dpif_offload_module_init(void); |
387 | | void dpif_offload_set_config(struct dpif *, const struct smap *other_cfg); |
388 | | void dpif_offload_port_add(struct dpif *, struct netdev *, odp_port_t); |
389 | | void dpif_offload_port_del(struct dpif *, odp_port_t); |
390 | | void dpif_offload_port_set_config(struct dpif *, odp_port_t, |
391 | | const struct smap *cfg); |
392 | | void dpif_offload_set_netdev_offload(struct netdev *, struct dpif_offload *); |
393 | | void dpif_offload_flow_dump_create(struct dpif_flow_dump *, |
394 | | const struct dpif *, bool terse); |
395 | | int dpif_offload_flow_dump_destroy(struct dpif_flow_dump *); |
396 | | int dpif_offload_flow_dump_next(struct dpif_flow_dump_thread *, |
397 | | struct dpif_flow *, int max_flows); |
398 | | void dpif_offload_flow_dump_thread_create(struct dpif_flow_dump_thread *, |
399 | | struct dpif_flow_dump *); |
400 | | void dpif_offload_flow_dump_thread_destroy(struct dpif_flow_dump_thread *); |
401 | | size_t dpif_offload_operate(struct dpif *, struct dpif_op **, size_t n_ops, |
402 | | enum dpif_offload_type offload_type); |
403 | | |
404 | | static inline void |
405 | | dpif_offload_assert_class(const struct dpif_offload *dpif_offload, |
406 | | const struct dpif_offload_class *dpif_offload_class) |
407 | 0 | { |
408 | 0 | ovs_assert(dpif_offload->class == dpif_offload_class); |
409 | 0 | } Unexecuted instantiation: dpif-offload.c:dpif_offload_assert_class Unexecuted instantiation: dpif-offload-dummy.c:dpif_offload_assert_class Unexecuted instantiation: dpif.c:dpif_offload_assert_class Unexecuted instantiation: dpif-offload-tc.c:dpif_offload_assert_class |
410 | | |
411 | | #endif /* DPIF_OFFLOAD_PROVIDER_H */ |