Coverage Report

Created: 2026-01-17 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 */