Coverage Report

Created: 2026-04-12 06:26

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
    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 */