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