xref: /dpdk/lib/dispatcher/rte_dispatcher.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2023 Ericsson AB
3  */
4 
5 #ifndef RTE_DISPATCHER_H
6 #define RTE_DISPATCHER_H
7 
8 /**
9  * @file
10  *
11  * RTE Dispatcher
12  *
13  * @warning
14  * @b EXPERIMENTAL:
15  * All functions in this file may be changed or removed without prior notice.
16  *
17  * The purpose of the dispatcher is to help decouple different parts
18  * of an application (e.g., modules), sharing the same underlying
19  * event device.
20  */
21 
22 #include <stdbool.h>
23 #include <stdint.h>
24 
25 #include <rte_compat.h>
26 #include <rte_eventdev.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /**
33  * Function prototype for match callbacks.
34  *
35  * Match callbacks are used by an application to decide how the
36  * dispatcher distributes events to different parts of the
37  * application.
38  *
39  * The application is not expected to process the event at the point
40  * of the match call. Such matters should be deferred to the process
41  * callback invocation.
42  *
43  * The match callback may be used as an opportunity to prefetch data.
44  *
45  * @param event
46  *  Pointer to event
47  *
48  * @param cb_data
49  *  The pointer supplied by the application in
50  *  rte_dispatcher_register().
51  *
52  * @return
53  *   Returns true in case this event should be delivered (via
54  *   the process callback), and false otherwise.
55  */
56 typedef bool (*rte_dispatcher_match_t)(const struct rte_event *event,
57 	void *cb_data);
58 
59 /**
60  * Function prototype for process callbacks.
61  *
62  * The process callbacks are used by the dispatcher to deliver
63  * events for processing.
64  *
65  * @param event_dev_id
66  *  The originating event device id.
67  *
68  * @param event_port_id
69  *  The originating event port.
70  *
71  * @param events
72  *  Pointer to an array of events.
73  *
74  * @param num
75  *  The number of events in the @p events array.
76  *
77  * @param cb_data
78  *  The pointer supplied by the application in
79  *  rte_dispatcher_register().
80  */
81 typedef void (*rte_dispatcher_process_t)(uint8_t event_dev_id,
82 	uint8_t event_port_id, struct rte_event *events, uint16_t num,
83 	void *cb_data);
84 
85 /**
86  * Function prototype for finalize callbacks.
87  *
88  * The finalize callbacks are used by the dispatcher to notify the
89  * application it has delivered all events from a particular batch
90  * dequeued from the event device.
91  *
92  * @param event_dev_id
93  *  The originating event device id.
94  *
95  * @param event_port_id
96  *  The originating event port.
97  *
98  * @param cb_data
99  *  The pointer supplied by the application in
100  *  rte_dispatcher_finalize_register().
101  */
102 typedef void (*rte_dispatcher_finalize_t)(uint8_t event_dev_id,
103 	uint8_t event_port_id, void *cb_data);
104 
105 /**
106  * Dispatcher statistics
107  */
108 struct rte_dispatcher_stats {
109 	/** Number of event dequeue calls made toward the event device. */
110 	uint64_t poll_count;
111 	/** Number of non-empty event batches dequeued from event device.*/
112 	uint64_t ev_batch_count;
113 	/** Number of events dispatched to a handler.*/
114 	uint64_t ev_dispatch_count;
115 	/** Number of events dropped because no handler was found. */
116 	uint64_t ev_drop_count;
117 };
118 
119 /**
120  * Create a dispatcher with the specified id.
121  *
122  * @param event_dev_id
123  *  The identifier of the event device from which this dispatcher
124  *  will dequeue events.
125  *
126  * @return
127  *   A pointer to a new dispatcher instance, or NULL on failure, in which
128  *   case rte_errno is set.
129  */
130 __rte_experimental
131 struct rte_dispatcher *
132 rte_dispatcher_create(uint8_t event_dev_id);
133 
134 /**
135  * Free a dispatcher.
136  *
137  * @param dispatcher
138  *  The dispatcher instance.
139  *
140  * @return
141  *  - 0: Success
142  *  - <0: Error code on failure
143  */
144 __rte_experimental
145 int
146 rte_dispatcher_free(struct rte_dispatcher *dispatcher);
147 
148 /**
149  * Retrieve the service identifier of a dispatcher.
150  *
151  * @param dispatcher
152  *  The dispatcher instance.
153  *
154  * @return
155  *  The dispatcher service's id.
156  */
157 __rte_experimental
158 uint32_t
159 rte_dispatcher_service_id_get(const struct rte_dispatcher *dispatcher);
160 
161 /**
162  * Binds an event device port to a specific lcore on the specified
163  * dispatcher.
164  *
165  * This function configures the event port id to be used by the event
166  * dispatcher service, if run on the specified lcore.
167  *
168  * Multiple event device ports may be bound to the same lcore. A
169  * particular port must not be bound to more than one lcore.
170  *
171  * If the dispatcher service is mapped (with rte_service_map_lcore_set())
172  * to a lcore to which no ports are bound, the service function will be a
173  * no-operation.
174  *
175  * This function may be called by any thread (including unregistered
176  * non-EAL threads), but not while the dispatcher is running on lcore
177  * specified by @c lcore_id.
178  *
179  * @param dispatcher
180  *  The dispatcher instance.
181  *
182  * @param event_port_id
183  *  The event device port identifier.
184  *
185  * @param batch_size
186  *  The batch size to use in rte_event_dequeue_burst(), for the
187  *  configured event device port and lcore.
188  *
189  * @param timeout
190  *  The timeout parameter to use in rte_event_dequeue_burst(), for the
191  *  configured event device port and lcore.
192  *
193  * @param lcore_id
194  *  The lcore by which this event port will be used.
195  *
196  * @return
197  *  - 0: Success
198  *  - -ENOMEM: Unable to allocate sufficient resources.
199  *  - -EEXISTS: Event port is already configured.
200  *  - -EINVAL: Invalid arguments.
201  */
202 __rte_experimental
203 int
204 rte_dispatcher_bind_port_to_lcore(struct rte_dispatcher *dispatcher,
205 	uint8_t event_port_id, uint16_t batch_size, uint64_t timeout,
206 	unsigned int lcore_id);
207 
208 /**
209  * Unbind an event device port from a specific lcore.
210  *
211  * This function may be called by any thread (including unregistered
212  * non-EAL threads), but not while the dispatcher is running on
213  * lcore specified by @c lcore_id.
214  *
215  * @param dispatcher
216  *  The dispatcher instance.
217  *
218  * @param event_port_id
219  *  The event device port identifier.
220  *
221  * @param lcore_id
222  *  The lcore which was using this event port.
223  *
224  * @return
225  *  - 0: Success
226  *  - -ENOENT: Event port id not bound to this @c lcore_id.
227  */
228 __rte_experimental
229 int
230 rte_dispatcher_unbind_port_from_lcore(struct rte_dispatcher *dispatcher,
231 	uint8_t event_port_id, unsigned int lcore_id);
232 
233 /**
234  * Register an event handler.
235  *
236  * The match callback function is used to select if a particular event
237  * should be delivered, using the corresponding process callback
238  * function.
239  *
240  * The reason for having two distinct steps is to allow the dispatcher
241  * to deliver all events as a batch. This in turn will cause
242  * processing of a particular kind of events to happen in a
243  * back-to-back manner, improving cache locality.
244  *
245  * The list of handler callback functions is shared among all lcores,
246  * but will only be executed on lcores which has an eventdev port
247  * bound to them, and which are running the dispatcher service.
248  *
249  * An event is delivered to at most one handler. Events where no
250  * handler is found are dropped.
251  *
252  * The application must not depend on the order of which the match
253  * functions are invoked.
254  *
255  * Ordering of events is not guaranteed to be maintained between
256  * different deliver callbacks. For example, suppose there are two
257  * callbacks registered, matching different subsets of events arriving
258  * on an atomic queue. A batch of events [ev0, ev1, ev2] are dequeued
259  * on a particular port, all pertaining to the same flow. The match
260  * callback for registration A returns true for ev0 and ev2, and the
261  * matching function for registration B for ev1. In that scenario, the
262  * dispatcher may choose to deliver first [ev0, ev2] using A's deliver
263  * function, and then [ev1] to B - or vice versa.
264  *
265  * rte_dispatcher_register() may be called by any thread
266  * (including unregistered non-EAL threads), but not while the event
267  * dispatcher is running on any service lcore.
268  *
269  * @param dispatcher
270  *  The dispatcher instance.
271  *
272  * @param match_fun
273  *  The match callback function.
274  *
275  * @param match_cb_data
276  *  A pointer to some application-specific opaque data (or NULL),
277  *  which is supplied back to the application when match_fun is
278  *  called.
279  *
280  * @param process_fun
281  *  The process callback function.
282  *
283  * @param process_cb_data
284  *  A pointer to some application-specific opaque data (or NULL),
285  *  which is supplied back to the application when process_fun is
286  *  called.
287  *
288  * @return
289  *  - >= 0: The identifier for this registration.
290  *  - -ENOMEM: Unable to allocate sufficient resources.
291  */
292 __rte_experimental
293 int
294 rte_dispatcher_register(struct rte_dispatcher *dispatcher,
295 	rte_dispatcher_match_t match_fun, void *match_cb_data,
296 	rte_dispatcher_process_t process_fun, void *process_cb_data);
297 
298 /**
299  * Unregister an event handler.
300  *
301  * This function may be called by any thread (including unregistered
302  * non-EAL threads), but not while the dispatcher is running on
303  * any service lcore.
304  *
305  * @param dispatcher
306  *  The dispatcher instance.
307  *
308  * @param handler_id
309  *  The handler registration id returned by the original
310  *  rte_dispatcher_register() call.
311  *
312  * @return
313  *  - 0: Success
314  *  - -EINVAL: The @c handler_id parameter was invalid.
315  */
316 __rte_experimental
317 int
318 rte_dispatcher_unregister(struct rte_dispatcher *dispatcher, int handler_id);
319 
320 /**
321  * Register a finalize callback function.
322  *
323  * An application may optionally install one or more finalize
324  * callbacks.
325  *
326  * All finalize callbacks are invoked by the dispatcher when a
327  * complete batch of events (retrieve using rte_event_dequeue_burst())
328  * have been delivered to the application (or have been dropped).
329  *
330  * The finalize callback is not tied to any particular handler.
331  *
332  * The finalize callback provides an opportunity for the application
333  * to do per-batch processing. One case where this may be useful is if
334  * an event output buffer is used, and is shared among several
335  * handlers. In such a case, proper output buffer flushing may be
336  * assured using a finalize callback.
337  *
338  * rte_dispatcher_finalize_register() may be called by any thread
339  * (including unregistered non-EAL threads), but not while the
340  * dispatcher is running on any service lcore.
341  *
342  * @param dispatcher
343  *  The dispatcher instance.
344  *
345  * @param finalize_fun
346  *  The function called after completing the processing of a
347  *  dequeue batch.
348  *
349  * @param finalize_data
350  *  A pointer to some application-specific opaque data (or NULL),
351  *  which is supplied back to the application when @c finalize_fun is
352  *  called.
353  *
354  * @return
355  *  - >= 0: The identifier for this registration.
356  *  - -ENOMEM: Unable to allocate sufficient resources.
357  */
358 __rte_experimental
359 int
360 rte_dispatcher_finalize_register(struct rte_dispatcher *dispatcher,
361 	rte_dispatcher_finalize_t finalize_fun, void *finalize_data);
362 
363 /**
364  * Unregister a finalize callback.
365  *
366  * This function may be called by any thread (including unregistered
367  * non-EAL threads), but not while the dispatcher is running on
368  * any service lcore.
369  *
370  * @param dispatcher
371  *  The dispatcher instance.
372  *
373  * @param reg_id
374  *  The finalize registration id returned by the original
375  *  rte_dispatcher_finalize_register() call.
376  *
377  * @return
378  *  - 0: Success
379  *  - -EINVAL: The @c reg_id parameter was invalid.
380  */
381 __rte_experimental
382 int
383 rte_dispatcher_finalize_unregister(struct rte_dispatcher *dispatcher, int reg_id);
384 
385 /**
386  * Start a dispatcher instance.
387  *
388  * Enables the dispatcher service.
389  *
390  * The underlying event device must have been started prior to calling
391  * rte_dispatcher_start().
392  *
393  * For the dispatcher to actually perform work (i.e., dispatch
394  * events), its service must have been mapped to one or more service
395  * lcores, and its service run state set to '1'. A dispatcher's
396  * service is retrieved using rte_dispatcher_service_id_get().
397  *
398  * Each service lcore to which the dispatcher is mapped should
399  * have at least one event port configured. Such configuration is
400  * performed by calling rte_dispatcher_bind_port_to_lcore(), prior to
401  * starting the dispatcher.
402  *
403  * @param dispatcher
404  *  The dispatcher instance.
405  */
406 __rte_experimental
407 void
408 rte_dispatcher_start(struct rte_dispatcher *dispatcher);
409 
410 /**
411  * Stop a running dispatcher instance.
412  *
413  * Disables the dispatcher service.
414  *
415  * @param dispatcher
416  *  The dispatcher instance.
417  */
418 __rte_experimental
419 void
420 rte_dispatcher_stop(struct rte_dispatcher *dispatcher);
421 
422 /**
423  * Retrieve statistics for a dispatcher instance.
424  *
425  * This function is MT safe and may be called by any thread
426  * (including unregistered non-EAL threads).
427  *
428  * @param dispatcher
429  *  The dispatcher instance.
430  * @param[out] stats
431  *   A pointer to a structure to fill with statistics.
432  */
433 __rte_experimental
434 void
435 rte_dispatcher_stats_get(const struct rte_dispatcher *dispatcher,
436 	struct rte_dispatcher_stats *stats);
437 
438 /**
439  * Reset statistics for a dispatcher instance.
440  *
441  * This function may be called by any thread (including unregistered
442  * non-EAL threads), but may not produce the correct result if the
443  * dispatcher is running on any service lcore.
444  *
445  * @param dispatcher
446  *  The dispatcher instance.
447  */
448 __rte_experimental
449 void
450 rte_dispatcher_stats_reset(struct rte_dispatcher *dispatcher);
451 
452 #ifdef __cplusplus
453 }
454 #endif
455 
456 #endif /* RTE_DISPATCHER_H */
457