EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
event_machine_odp_ext.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015-2026, Nokia Solutions and Networks
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * @file
33 * Event Machine ODP API extensions
34 *
35 */
36
37#ifndef _GNU_SOURCE
38#define _GNU_SOURCE
39#endif
40
41#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
44
45#include <stdint.h>
46#include <string.h>
47
48#include <odp_api.h>
49
50#include <event_machine.h>
52
53#include "em_chaining.h"
54#include "em_error.h"
55#include "em_event.h"
56#include "em_event_inline.h"
57#include "em_event_state.h"
58#include "em_event_types.h"
59#include "em_mem.h"
60#include "em_pool.h"
61#include "em_pool_inline.h"
62#include "em_pool_types.h"
63#include "em_queue.h"
64#include "em_queue_group.h"
65#include "em_queue_inline.h"
66#include "em_queue_types.h"
67
68odp_queue_t em_odp_queue_odp(em_queue_t queue)
69{
70 const queue_elem_t *queue_elem = queue_elem_get(queue);
71
72 if (EM_CHECK_LEVEL > 0 && unlikely(queue_elem == NULL)) {
74 "queue_elem ptr NULL!");
75 return ODP_QUEUE_INVALID;
76 }
77
78 return queue_elem->odp_queue;
79}
80
81em_queue_t em_odp_queue_em(odp_queue_t queue)
82{
83 const queue_elem_t *queue_elem = odp_queue_context(queue);
84
85 /* verify that the odp context is an EM queue elem */
86 if (EM_CHECK_LEVEL > 0 &&
87 unlikely(!queue_elem || queue_elem->valid_check != QUEUE_ELEM_VALID))
88 return EM_QUEUE_UNDEF;
89
90 if (EM_CHECK_LEVEL >= 2 && unlikely(!queue_allocated(queue_elem))) {
92 "EM Queue deleted (or not created)! ODP-queue:%" PRIu64 "",
93 odp_queue_to_u64(queue));
94 return EM_QUEUE_UNDEF;
95 }
96
97 return (em_queue_t)(uintptr_t)queue_elem->queue;
98}
99
100/**
101 * @brief Helper to em_odp_pktin_event_queues2em()
102 *
103 * @param odp_queue ODP pktin-queue to convert to an EM-queue.
104 * The given ODP queue handle must have been returned by
105 * odp_pktin_event_queue().
106 * @return em_queue_t: New EM queue mapped to use the ODP pktin event queue
107 */
108static em_queue_t pktin_event_queue2em(odp_queue_t odp_queue)
109{
110 em_queue_t queue = EM_QUEUE_UNDEF; /* return value */
111 const char *err_str = "";
112 odp_queue_info_t odp_qinfo;
113 int ret = 0;
114
115 if (unlikely(odp_queue == ODP_QUEUE_INVALID)) {
117 "Bad arg: ODP queue invalid!");
118 return EM_QUEUE_UNDEF;
119 }
120
121 queue = em_odp_queue_em(odp_queue);
122 if (unlikely(queue != EM_QUEUE_UNDEF)) {
123 /* The given ODP queue is already associated with an EM queue */
124 return queue;
125 }
126
127 ret = odp_queue_info(odp_queue, &odp_qinfo);
128 if (unlikely(ret || odp_qinfo.param.type != ODP_QUEUE_TYPE_SCHED)) {
129 err_str = "odp_queue_info(): unsuitable odp queue";
130 goto err_return;
131 }
132
133 /*
134 * Determine EM queue priority:
135 */
136 odp_schedule_prio_t odp_prio = odp_schedule_default_prio();
138 int num_prio = em_queue_num_prio(NULL);
139
140 for (int i = 0; i < num_prio; i++) {
141 int err = prio_em2odp(i, &odp_prio/*out*/);
142
143 if (!err && odp_prio == odp_qinfo.param.sched.prio) {
144 prio = i;
145 break;
146 }
147 }
148 if (unlikely(prio == EM_QUEUE_PRIO_UNDEF)) {
149 err_str = "Can't convert ODP qprio to EM qprio";
150 goto err_return;
151 }
152
153 /*
154 * Determine scheduled EM queue type
155 */
157
158 ret = scheduled_queue_type_odp2em(odp_qinfo.param.sched.sync,
159 &queue_type /*out*/);
160 if (unlikely(ret)) {
161 err_str = "Can't convert ODP qtype to EM qtype";
162 goto err_return;
163 }
164
165 /*
166 * Determine EM queue group
167 */
168 em_queue_group_t queue_group;
169 const queue_group_elem_t *qgrp_elem;
170
171 queue_group = em_queue_group_first(NULL);
172 while (queue_group != EM_QUEUE_GROUP_UNDEF) {
173 qgrp_elem = queue_group_elem_get(queue_group);
174 if (qgrp_elem &&
175 qgrp_elem->odp_sched_group == odp_qinfo.param.sched.group)
176 break; /* found match! */
177 queue_group = em_queue_group_next();
178 }
179 if (unlikely(queue_group == EM_QUEUE_GROUP_UNDEF)) {
180 err_str = "No matching EM Queue Group found";
181 goto err_return;
182 }
183
184 /*
185 * Set EM queue name based on the ODP queue name
186 */
187 char q_name[ODP_QUEUE_NAME_LEN];
188
189 snprintf(q_name, sizeof(q_name), "EM:%s", odp_qinfo.name);
190 q_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
191
192 /*
193 * Set up the EM queue based on gathered info
194 */
195 em_queue_param_t param;
196
197 em_queue_param_init(&param);
198 param.type = queue_type;
199 param.prio = prio;
200 param.queue_group = queue_group;
201
202 queue = queue_alloc(EM_QUEUE_UNDEF, &err_str);
203 if (unlikely(queue == EM_QUEUE_UNDEF))
204 goto err_return; /* err_str set by queue_alloc() */
205
206 queue_elem_t *q_elem = queue_elem_get(queue);
207
208 if (unlikely(!q_elem)) {
209 err_str = "Queue elem NULL!";
210 goto err_return;
211 }
212
213 /* Set common queue-elem fields based on 'param' */
214 queue_setup_common(q_name, &param, q_elem /*in/out*/);
215 /* Set queue-elem fields for a pktin event queue */
216 q_elem->odp_queue = odp_queue;
217 q_elem->flags.is_pktin = true;
218 q_elem->flags.scheduled = true;
219 q_elem->state = EM_QUEUE_STATE_INIT;
220
221 /*
222 * Note: The ODP queue context points to the EM queue elem.
223 * The EM queue context set by the user using the API function
224 * em_queue_set_context() is accessed through the queue_elem_t::context
225 * and retrieved with em_queue_context() or passed by EM to the
226 * EO-receive function for scheduled queues.
227 *
228 * Set the odp context data length (in bytes) for potential prefetching.
229 * The ODP implementation may use this value as a hint for the number
230 * of context data bytes to prefetch.
231 */
232 ret = odp_queue_context_set(odp_queue, q_elem, sizeof(*q_elem));
233 if (unlikely(ret)) {
234 err_str = "odp_queue_context_set() failed";
235 goto err_return;
236 }
237
238 return queue; /* success */
239
240err_return:
242 "%s (ret=%d)", err_str, ret);
243 if (EM_DEBUG_PRINT_BASE && odp_queue != ODP_QUEUE_INVALID)
244 odp_queue_print(odp_queue);
245 if (queue != EM_QUEUE_UNDEF)
246 queue_free(queue);
247 return EM_QUEUE_UNDEF;
248}
249
250int em_odp_pktin_event_queues2em(const odp_queue_t odp_pktin_event_queues[/*num*/],
251 em_queue_t queues[/*out:num*/], int num)
252{
253 int i;
254
255 for (i = 0; i < num; i++) {
256 queues[i] = pktin_event_queue2em(odp_pktin_event_queues[i]);
257 if (unlikely(queues[i] == EM_QUEUE_UNDEF)) {
259 "Cannot create EM-Q using pktin-queue:%d (hdl:%" PRIu64 ")",
260 i, odp_queue_to_u64(odp_pktin_event_queues[i]));
261 break;
262 }
263 }
264
265 return i;
266}
267
269{
270 return sizeof(event_hdr_t);
271}
272
273odp_event_t em_odp_event2odp(em_event_t event)
274{
275 return event_em2odp(event);
276}
277
278void em_odp_events2odp(const em_event_t events[/*num*/],
279 odp_event_t odp_events[/*out:num*/], int num)
280{
281 if (unlikely(num <= 0))
282 return;
283
284 events_em2odp(events, odp_events/*out*/, num);
285}
286
287em_event_t em_odp_event2em(odp_event_t odp_event)
288{
289 em_event_t event = event_init_odp(odp_event, false/*!is_extev*/,
290 NULL/*disp_q_elem*/, NULL/*ev_hdr__out*/);
291
292 return event;
293}
294
295void em_odp_events2em(const odp_event_t odp_events[/*num*/],
296 em_event_t events[/*out:num*/], int num)
297{
298 if (unlikely(num <= 0))
299 return;
300
301 event_hdr_t *ev_hdrs[num];
302
303 event_init_odp_multi(odp_events, events/*out*/, ev_hdrs/*out*/, num,
304 false/*!is_extev*/, NULL/*disp_q_elem*/);
305}
306
307int em_odp_pool2odp(em_pool_t pool, odp_pool_t odp_pools[/*out*/], int num)
308{
309 const mpool_elem_t *pool_elem = pool_elem_get(pool);
310
311 if (EM_CHECK_LEVEL > 0 &&
312 unlikely(!pool_elem || !odp_pools || num <= 0)) {
314 "Inv.args: pool:%" PRI_POOL " odp_pools:%p num:%d",
315 pool, odp_pools, num);
316 return 0;
317 }
318 if (EM_CHECK_LEVEL >= 2 && unlikely(!pool_allocated(pool_elem)))
320 "Pool:%" PRI_POOL " not created", pool);
321
322 const int num_subpools = MIN(num, pool_elem->num_subpools);
323
324 /* copy for(each i): odp_pools[i] = pool_elem->odp_pool[i] */
325 memcpy(odp_pools, pool_elem->odp_pool, num_subpools * sizeof(odp_pool_t));
326
327 /* return the number of odp-pools filled into 'odp_pools[]' */
328 return num_subpools;
329}
330
331em_pool_t em_odp_pool2em(odp_pool_t odp_pool)
332{
333 if (EM_CHECK_LEVEL > 0 && unlikely(odp_pool == ODP_POOL_INVALID)) {
335 "Inv.arg: odp_pool invalid");
336 return EM_POOL_UNDEF;
337 }
338
339 return pool_odp2em(odp_pool);
340}
341
342static inline int
343pkt_enqueue_scheduled(const odp_packet_t pkt_tbl[/*num*/], int num,
344 const queue_elem_t *q_elem)
345{
346 odp_event_t odp_event_tbl[num];
347
348 odp_packet_to_event_multi(pkt_tbl, odp_event_tbl/*out*/, num);
349
350 /*
351 * Enqueue the events into a scheduled em-odp queue.
352 * No need to init the ev-hdrs - init is done in dispatch.
353 */
354 int sent = odp_queue_enq_multi(q_elem->odp_queue,
355 odp_event_tbl, num);
356 if (unlikely(sent < num)) {
357 sent = unlikely(sent < 0) ? 0 : sent;
358 odp_packet_free_multi(&pkt_tbl[sent], num - sent);
359 /*
360 * Event state checking: No need to adjust the event state
361 * since the events were never enqueued into EM.
362 */
363 }
364
365 return sent;
366}
367
368static inline int
369pkt_enqueue_local(const odp_packet_t pkt_tbl[/*num*/], int num,
370 const queue_elem_t *q_elem)
371{
372 odp_event_t odp_event_tbl[num];
373 em_event_t event_tbl[num];
374
375 odp_packet_to_event_multi(pkt_tbl, odp_event_tbl/*out*/, num);
376
377 events_odp2em(odp_event_tbl, event_tbl/*out*/, num);
378
379 /*
380 * Send into an local em-odp queue.
381 * No need to init the ev-hdrs - init is done in dispatch.
382 */
383 int sent = send_local_multi(event_tbl, num, q_elem);
384
385 if (unlikely(sent < num)) {
386 sent = unlikely(sent < 0) ? 0 : sent;
387 odp_packet_free_multi(&pkt_tbl[sent], num - sent);
388 /*
389 * Event state checking: No need to adjust the event state
390 * since the events were never enqueued into EM.
391 */
392 }
393
394 return sent;
395}
396
397static inline int
398pkt_enqueue_chaining_out(const odp_packet_t pkt_tbl[/*num*/], int num,
399 em_queue_t queue)
400{
401 odp_event_t odp_event_tbl[num];
402 em_event_t event_tbl[num];
403 event_hdr_t *evhdr_tbl[num];
404 int sent = 0;
405
406 odp_packet_to_event_multi(pkt_tbl, odp_event_tbl/*out*/, num);
407
408 events_odp2em(odp_event_tbl, event_tbl/*out*/, num);
409
410 /* Init the event-hdrs for incoming non-scheduled pkts */
411 event_init_pkt_multi(pkt_tbl, event_tbl/*in/out*/,
412 evhdr_tbl/*out*/, num, true /*is_extev*/);
413
414 /* Send directly out via event chaining */
415 if (likely(queue_external(queue)))
416 sent = send_chaining_multi(event_tbl, num, queue);
417
418 if (unlikely(sent < num)) {
419 sent = unlikely(sent < 0) ? 0 : sent;
420 em_free_multi(&event_tbl[sent], num - sent);
421 }
422
423 return sent;
424}
425
426static inline int
427pkt_enqueue_unscheduled(const odp_packet_t pkt_tbl[/*num*/], int num,
428 const queue_elem_t *q_elem)
429{
430 odp_event_t odp_event_tbl[num];
431 em_event_t event_tbl[num];
432 event_hdr_t *evhdr_tbl[num];
433
434 odp_packet_to_event_multi(pkt_tbl, odp_event_tbl/*out*/, num);
435
436 events_odp2em(odp_event_tbl, event_tbl/*out*/, num);
437
438 /* Init the event-hdrs for incoming non-scheduled pkts */
439 event_init_pkt_multi(pkt_tbl, event_tbl/*in/out*/,
440 evhdr_tbl/*out*/, num, true /*is_extev*/);
441
442 /* Enqueue into an unscheduled em-odp queue */
443 int sent = odp_queue_enq_multi(q_elem->odp_queue, odp_event_tbl, num);
444
445 if (unlikely(sent < num)) {
446 sent = unlikely(sent < 0) ? 0 : sent;
447 em_free_multi(&event_tbl[sent], num - sent);
448 }
449
450 return sent;
451}
452
453static inline int
454pkt_enqueue_output(const odp_packet_t pkt_tbl[/*num*/], int num,
455 queue_elem_t *const q_elem)
456{
457 odp_event_t odp_event_tbl[num];
458 em_event_t event_tbl[num];
459 event_hdr_t *evhdr_tbl[num];
460
461 odp_packet_to_event_multi(pkt_tbl, odp_event_tbl/*out*/, num);
462
463 events_odp2em(odp_event_tbl, event_tbl/*out*/, num);
464
465 /* Init the event-hdrs for incoming non-scheduled pkts */
466 event_init_pkt_multi(pkt_tbl, event_tbl/*in/out*/,
467 evhdr_tbl/*out*/, num, true /*is_extev*/);
468
469 /* Send directly out via an output em-odp queue */
470 int sent = send_output_multi(event_tbl, num, q_elem);
471
472 if (unlikely(sent < num)) {
473 sent = unlikely(sent < 0) ? 0 : sent;
474 em_free_multi(&event_tbl[sent], num - sent);
475 }
476
477 return sent;
478}
479
480int em_odp_pkt_enqueue(const odp_packet_t pkt_tbl[/*num*/], int num, em_queue_t queue)
481{
482 if (unlikely(!pkt_tbl || num <= 0))
483 return 0;
484
485 queue_elem_t *const q_elem = queue_elem_get(queue);
486
487 /* Queue not in this EM instance, send directly out via event chaining */
488 if (!q_elem)
489 return pkt_enqueue_chaining_out(pkt_tbl, num, queue);
490
491 if (q_elem->flags.scheduled)
492 return pkt_enqueue_scheduled(pkt_tbl, num, q_elem);
493
494 if (q_elem->type == EM_QUEUE_TYPE_LOCAL)
495 return pkt_enqueue_local(pkt_tbl, num, q_elem);
496
497 if (q_elem->type == EM_QUEUE_TYPE_UNSCHEDULED)
498 return pkt_enqueue_unscheduled(pkt_tbl, num, q_elem);
499
500 if (q_elem->type == EM_QUEUE_TYPE_OUTPUT)
501 return pkt_enqueue_output(pkt_tbl, num, q_elem);
502
503 /* No supported queue type, drop all pkts */
504 odp_packet_free_multi(pkt_tbl, num);
505 /*
506 * Event state checking: No need to adjust the event state
507 * since the pkts/events were neither initialized nor enqueued into EM.
508 */
509 return 0;
510}
511
512odp_schedule_group_t em_odp_qgrp2odp(em_queue_group_t queue_group)
513{
514 const queue_group_elem_t *qgrp_elem = queue_group_elem_get(queue_group);
515
516 if (unlikely(EM_CHECK_LEVEL > 0 && !qgrp_elem)) {
518 "Invalid queue group:%" PRI_QGRP "", queue_group);
519 return ODP_SCHED_GROUP_INVALID;
520 }
521 if (unlikely(EM_CHECK_LEVEL >= 2 && !queue_group_allocated(qgrp_elem))) {
523 "Queue group:%" PRI_QGRP " not created", queue_group);
524 return ODP_SCHED_GROUP_INVALID;
525 }
526
527 return qgrp_elem->odp_sched_group;
528}
529
530odp_timer_pool_t em_odp_timer2odp(em_timer_t tmr)
531{
532 unsigned int i = ((unsigned int)((uintptr_t)(tmr) - 1)); /* TMR_H2I */
533
534 if (unlikely(EM_CHECK_LEVEL > 0 && i >= EM_ODP_MAX_TIMERS))
535 return ODP_TIMER_POOL_INVALID;
536
537 const timer_storage_t *const tmrs = &em_shm->timers;
538
539 return tmrs->timer[i].odp_tmr_pool;
540}
541
542odp_timer_t em_odp_tmo2odp(em_tmo_t tmo)
543{
544 if (unlikely(EM_CHECK_LEVEL > 0 && tmo == EM_TMO_UNDEF))
545 return ODP_TIMER_INVALID;
546
547 return tmo->odp_timer;
548}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
struct event_hdr event_hdr_t
em_shm_t * em_shm
@ EM_QUEUE_STATE_INIT
#define EM_CHECK_LEVEL
#define EM_DEBUG_PRINT_BASE
#define EM_QUEUE_GROUP_UNDEF
#define PRI_POOL
#define EM_POOL_UNDEF
#define PRI_QGRP
#define EM_QUEUE_UNDEF
#define EM_ESCOPE_ODP_EXT
@ EM_ERR_OPERATION_FAILED
@ EM_ERR_NOT_CREATED
@ EM_ERR_BAD_ARG
void em_free_multi(em_event_t events[], int num)
int em_odp_pkt_enqueue(const odp_packet_t pkt_tbl[], int num, em_queue_t queue)
odp_schedule_group_t em_odp_qgrp2odp(em_queue_group_t queue_group)
Get the ODP schedule group that corresponds to the given EM queue group.
int em_odp_pool2odp(em_pool_t pool, odp_pool_t odp_pools[], int num)
Get the ODP pools used as subpools in a given EM event pool.
em_pool_t em_odp_pool2em(odp_pool_t odp_pool)
Get the EM event pool that the given ODP pool belongs to.
odp_event_t em_odp_event2odp(em_event_t event)
odp_timer_t em_odp_tmo2odp(em_tmo_t tmo)
Get the odp timer from EM timeout handle.
int em_odp_pktin_event_queues2em(const odp_queue_t odp_pktin_event_queues[], em_queue_t queues[], int num)
Map the given scheduled ODP pktin event queues to new EM queues.
em_queue_t em_odp_queue_em(odp_queue_t queue)
void em_odp_events2em(const odp_event_t odp_events[], em_event_t events[], int num)
odp_timer_pool_t em_odp_timer2odp(em_timer_t tmr)
Get the odp timer_pool from EM timer handle.
uint32_t em_odp_event_hdr_size(void)
void em_odp_events2odp(const em_event_t events[], odp_event_t odp_events[], int num)
odp_queue_t em_odp_queue_odp(em_queue_t queue)
em_event_t em_odp_event2em(odp_event_t odp_event)
em_queue_group_t em_queue_group_first(unsigned int *num)
em_queue_group_t em_queue_group_next(void)
#define EM_QUEUE_PRIO_UNDEF
uint32_t em_queue_type_t
uint32_t em_queue_prio_t
void em_queue_param_init(em_queue_param_t *param)
int em_queue_num_prio(int *num_runtime)
@ EM_QUEUE_TYPE_UNSCHEDULED
@ EM_QUEUE_TYPE_UNDEF
@ EM_QUEUE_TYPE_LOCAL
@ EM_QUEUE_TYPE_OUTPUT
em_queue_group_t queue_group
odp_pool_t odp_pool[EM_MAX_SUBPOOLS]
odp_queue_t odp_queue
queue_state_t state
uint16_t valid_check
queue_elem_flags_t flags
odp_schedule_group_t odp_sched_group