EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
event_machine_packet.c
1/*
2 * Copyright (c) 2024-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#ifndef _GNU_SOURCE
32#define _GNU_SOURCE
33#endif
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <stdbool.h>
40#include <stdint.h>
41#include <string.h>
42
43#include <odp_api.h>
44
45#include <event_machine.h>
46
47#include "em_error.h"
48#include "em_event.h"
49#include "em_event_inline.h"
50#include "em_event_state.h"
51#include "em_event_types.h"
52#include "em_mem.h"
53#include "em_pool.h"
54#include "em_pool_inline.h"
55#include "em_pool_types.h"
56
57static inline bool is_odp_packet(odp_event_t odp_event)
58{
59 if (unlikely(odp_event == ODP_EVENT_INVALID ||
60 odp_event_type(odp_event) != ODP_EVENT_PACKET))
61 return false;
62
63 return true;
64}
65
66void *em_packet_pointer(em_event_t pktev)
67{
68 odp_event_t odp_event = event_em2odp(pktev);
69
70 if (EM_CHECK_LEVEL >= 3 &&
71 unlikely(!is_odp_packet(odp_event))) {
72 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_POINTER,
73 "Invalid packet event");
74 return NULL;
75 }
76
77 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
78
79 return odp_packet_data(odp_pkt);
80}
81
82uint32_t em_packet_size(em_event_t pktev)
83{
84 odp_event_t odp_event = event_em2odp(pktev);
85
86 if (EM_CHECK_LEVEL >= 3 &&
87 unlikely(!is_odp_packet(odp_event))) {
88 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_SIZE,
89 "Invalid packet event");
90 return 0;
91 }
92
93 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
94 uint32_t seg_len = odp_packet_seg_len(odp_pkt);
95
96 return seg_len;
97}
98
99void *em_packet_pointer_and_size(em_event_t pktev, uint32_t *size /*out*/)
100{
101 odp_event_t odp_event = event_em2odp(pktev);
102
103 if (EM_CHECK_LEVEL >= 3 &&
104 unlikely(!is_odp_packet(odp_event))) {
105 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_POINTER_AND_SIZE,
106 "Invalid packet event");
107 return NULL;
108 }
109
110 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
111
112 if (!size) {
113 /* User not interested in 'size',
114 * fall back to em_packet_pointer() functionality
115 */
116 return odp_packet_data(odp_pkt);
117 }
118
119 return odp_packet_data_seg_len(odp_pkt, size /*out*/);
120}
121
122void *em_packet_resize(em_event_t pktev, uint32_t size)
123{
124 odp_event_t odp_event = event_em2odp(pktev);
125
126 if (EM_CHECK_LEVEL >= 3 &&
127 unlikely(!is_odp_packet(odp_event))) {
128 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_RESIZE,
129 "Invalid packet event");
130 return NULL;
131 }
132
133 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
134 uint32_t seg_len = odp_packet_seg_len(odp_pkt);
135 const void *tail;
136
137 if (EM_CHECK_LEVEL >= 3) {
138 uint32_t tailroom = odp_packet_tailroom(odp_pkt);
139
140 if (unlikely(size == 0 || size > seg_len + tailroom)) {
141 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_RESIZE,
142 "Invalid packet resize:%u > max:%u",
143 size, seg_len + tailroom);
144 return NULL;
145 }
146 }
147
148 if (size > seg_len)
149 tail = odp_packet_push_tail(odp_pkt, size - seg_len);
150 else /* size <= seg_len */
151 tail = odp_packet_pull_tail(odp_pkt, seg_len - size);
152
153 if (unlikely(!tail))
154 return NULL;
155
156 return odp_packet_data(odp_pkt);
157}
158
159uint32_t em_packet_headroom(em_event_t pktev)
160{
161 odp_event_t odp_event = event_em2odp(pktev);
162
163 if (EM_CHECK_LEVEL >= 3 &&
164 unlikely(!is_odp_packet(odp_event))) {
165 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_HEADROOM,
166 "Invalid packet event");
167 return 0;
168 }
169
170 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
171
172 return odp_packet_headroom(odp_pkt);
173}
174
175uint32_t em_packet_tailroom(em_event_t pktev)
176{
177 odp_event_t odp_event = event_em2odp(pktev);
178
179 if (EM_CHECK_LEVEL >= 3 &&
180 unlikely(!is_odp_packet(odp_event))) {
181 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_TAILROOM,
182 "Invalid packet event");
183 return 0;
184 }
185
186 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
187
188 return odp_packet_tailroom(odp_pkt);
189}
190
191void *em_packet_push_head(em_event_t pktev, uint32_t len)
192{
193 odp_event_t odp_event = event_em2odp(pktev);
194
195 if (EM_CHECK_LEVEL >= 3 &&
196 unlikely(!is_odp_packet(odp_event))) {
197 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PUSH_HEAD,
198 "Invalid packet event");
199 return NULL;
200 }
201
202 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
203 void *ptr = odp_packet_push_head(odp_pkt, len);
204
205 if (EM_CHECK_LEVEL >= 3 && unlikely(!ptr)) {
206 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PUSH_HEAD,
207 "packet push head failed, check len=%u", len);
208 return NULL;
209 }
210
211 return ptr;
212}
213
214void *em_packet_pull_head(em_event_t pktev, uint32_t len)
215{
216 odp_event_t odp_event = event_em2odp(pktev);
217
218 if (EM_CHECK_LEVEL >= 3 &&
219 unlikely(!is_odp_packet(odp_event))) {
220 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PULL_HEAD,
221 "Invalid packet event");
222 return NULL;
223 }
224
225 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
226 void *ptr = odp_packet_pull_head(odp_pkt, len);
227
228 if (EM_CHECK_LEVEL >= 3 && unlikely(!ptr)) {
229 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PULL_HEAD,
230 "packet pull head failed, check len=%u", len);
231 return NULL;
232 }
233
234 return ptr;
235}
236
237void *em_packet_push_tail(em_event_t pktev, uint32_t len)
238{
239 odp_event_t odp_event = event_em2odp(pktev);
240
241 if (EM_CHECK_LEVEL >= 3 &&
242 unlikely(!is_odp_packet(odp_event))) {
243 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PUSH_TAIL,
244 "Invalid packet event");
245 return NULL;
246 }
247
248 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
249 void *ptr = odp_packet_push_tail(odp_pkt, len);
250
251 if (EM_CHECK_LEVEL >= 3 && unlikely(!ptr)) {
252 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PUSH_TAIL,
253 "packet push tail failed, check len=%u", len);
254 return NULL;
255 }
256
257 return ptr;
258}
259
260void *em_packet_pull_tail(em_event_t pktev, uint32_t len)
261{
262 odp_event_t odp_event = event_em2odp(pktev);
263
264 if (EM_CHECK_LEVEL >= 3 &&
265 unlikely(!is_odp_packet(odp_event))) {
266 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PULL_TAIL,
267 "Invalid packet event");
268 return NULL;
269 }
270
271 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
272 void *ptr = odp_packet_pull_tail(odp_pkt, len);
273
274 if (EM_CHECK_LEVEL >= 3 && unlikely(!ptr)) {
275 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_PULL_TAIL,
276 "packet pull tail failed, check len=%u", len);
277 return NULL;
278 }
279
280 return ptr;
281}
282
283em_status_t em_packet_reset(em_event_t pktev, uint32_t size)
284{
285 odp_event_t odp_event = event_em2odp(pktev);
286
287 RETURN_ERROR_IF(EM_CHECK_LEVEL >= 3 && !is_odp_packet(odp_event),
288 EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_RESET,
289 "Invalid packet event");
290
291 odp_packet_t odp_pkt = odp_packet_from_event(odp_event);
292 odp_pool_t odp_pool = odp_packet_pool(odp_pkt);
293 em_pool_t pool = pool_odp2em(odp_pool);
294 const mpool_elem_t *pool_elem = pool_elem_get(pool);
295
296 RETURN_ERROR_IF(!pool_elem || (EM_CHECK_LEVEL >= 3 && !pool_allocated(pool_elem)),
297 EM_ERR_BAD_ID, EM_ESCOPE_PACKET_RESET,
298 "Invalid EM pool:%" PRI_POOL "", pool);
299
300 const uint32_t push_head_len = pool_elem->align_offset;
301 uint32_t pull_tail_len;
302 uint32_t reset_len;
303
304 if (size > push_head_len) {
305 reset_len = size - push_head_len;
306 pull_tail_len = 0;
307 } else {
308 reset_len = 1; /* min allowed */
309 pull_tail_len = push_head_len + 1 - size;
310 }
311
312 int ret = odp_packet_reset(odp_pkt, reset_len);
313
314 RETURN_ERROR_IF(ret, EM_ERR_LIB_FAILED, EM_ESCOPE_PACKET_RESET,
315 "odp-packet reset failed:%d", ret);
316
317 /* Adjust event payload start-address based on alignment config */
318 if (push_head_len) {
319 const void *ptr = odp_packet_push_head(odp_pkt, push_head_len);
320
321 RETURN_ERROR_IF(EM_CHECK_LEVEL >= 3 && !ptr,
322 EM_ERR_LIB_FAILED, EM_ESCOPE_PACKET_RESET,
323 "odp_packet_push_head() failed");
324 }
325 if (pull_tail_len) {
326 const void *ptr = odp_packet_pull_tail(odp_pkt, pull_tail_len);
327
328 RETURN_ERROR_IF(EM_CHECK_LEVEL >= 3 && !ptr,
329 EM_ERR_LIB_FAILED, EM_ESCOPE_PACKET_RESET,
330 "odp_packet_pull_tail() failed");
331 }
332
333 /*
334 * Set the pkt user ptr to be able to recognize pkt-events that
335 * EM has created vs pkts from pkt-input that needs their
336 * ev-hdrs to be initialized.
337 */
338 odp_packet_user_flag_set(odp_pkt, USER_FLAG_SET);
339
340 event_hdr_t *const ev_hdr = odp_packet_user_area(odp_pkt);
341 ev_hdr_user_area_t uarea_save = ev_hdr->user_area;
342
343 ev_hdr->event_size = size; /* store new 'original' size */
344 ev_hdr->egrp = EM_EVENT_GROUP_UNDEF;
345 ev_hdr->user_area.all = 0;
346 ev_hdr->user_area.size = uarea_save.size;
347 ev_hdr->user_area.isinit = 1;
348
349 return EM_OK;
350}
351
352/**
353 * Helper function for em_packet_concat() checks whether the event pointer has
354 * changed, updates the new handle with the correct evgen, and modifies the
355 * event header accordingly.
356 */
357static inline em_event_t
358check_update_event(evhdl_t original_hdl, evhdl_t updated_hdl, event_hdr_t *updated_hdr)
359{
360 if (original_hdl.evptr != updated_hdl.evptr) {
361 /* update event handle and ev_hdr, ev_hdr is copied from original first_pkt */
362 updated_hdl.evgen = original_hdl.evgen;
363 updated_hdr->event = updated_hdl.event;
364 return updated_hdl.event;
365 }
366 return original_hdl.event;
367}
368
369/**
370 * Helper function for em_packet_concat(), does a packet copy if the second_pkt
371 * has references.
372 *
373 * Only needed with ODP API < 1.50, where odp_packet_concat() does not support a
374 * 'src' packet that has references. ODP API >= 1.50 handles this natively.
375 */
376static inline em_status_t
377concat_packet_with_ref(em_event_t *first_pkt, em_event_t second_pkt)
378{
379 odp_event_t odp_event_first = event_em2odp(*first_pkt);
380 odp_event_t odp_event_second = event_em2odp(second_pkt);
381
382 if (unlikely(EM_CHECK_LEVEL >= 3 &&
383 (!is_odp_packet(odp_event_first) ||
384 !is_odp_packet(odp_event_second)))) {
385 (void)INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_CONCAT,
386 "first_pkt and/or second_pkt not a packet");
387 return -1;
388 }
389
390 const bool esv_ena = esv_enabled();
391 event_hdr_t *ev_hdr_first;
392
393 /* Save event hdl for checking if it has changed */
394 evhdl_t first_ev = {.event = *first_pkt};
395
396 odp_packet_t odp_pkt_first = odp_packet_from_event(odp_event_first);
397 odp_packet_t odp_pkt_second = odp_packet_from_event(odp_event_second);
398 uint32_t first_len = odp_packet_len(odp_pkt_first);
399 uint32_t second_len = odp_packet_len(odp_pkt_second);
400
401 /* Mark first_pkt as free, since ODP might free it */
402 if (esv_ena) {
403 ev_hdr_first = odp_packet_user_area(odp_pkt_first);
404 evstate_free(*first_pkt, ev_hdr_first, EVSTATE__MARK_FREE);
405 }
406 /* Increase packet data length to fit the second_pkt data */
407 int ret = odp_packet_extend_tail(&odp_pkt_first, second_len, NULL, NULL);
408
409 if (unlikely(ret < 0)) {
410 if (esv_ena)
411 evstate_unmark_free(*first_pkt, ev_hdr_first, EVSTATE__UNMARK_FREE);
412
413 return -1;
414 }
415 /* Copy second_pkt data to the first_pkt */
416 (void)odp_packet_copy_from_pkt(odp_pkt_first, first_len,
417 odp_pkt_second, 0, second_len);
418 evhdl_t ev_hdl_updated = {.event = event_odp2em(odp_packet_to_event(odp_pkt_first))};
419
420 ev_hdr_first = odp_packet_user_area(odp_pkt_first);
421
422 /* Check if event handle has changed, and update it */
423 *first_pkt = check_update_event(first_ev, ev_hdl_updated, ev_hdr_first);
424
425 /* Unmark free resulted first_pkt */
426 if (esv_ena)
427 evstate_unmark_free(*first_pkt, ev_hdr_first, EVSTATE__UNMARK_FREE);
428
429 em_free(second_pkt);
430
431 /* Packet data was copied */
432 return 1;
433}
434
435int em_packet_concat(em_event_t *first_pkt /*in,out*/, em_event_t second_pkt)
436{
437 if (unlikely(EM_CHECK_LEVEL >= 3 && event_has_ref(*first_pkt))) {
438 (void)INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_CONCAT,
439 "first_pkt has a reference");
440 return -1;
441 }
442
443 if (ODP_VERSION_API_NUM(1, 50, 0) > ODP_VERSION_API &&
444 unlikely(event_has_ref(second_pkt))) {
445 /*
446 * ODP API < 1.50 does not support packet concatenating if second_pkt has
447 * references, so fall back to a manual data copy. ODP API >= 1.50 handles
448 * a referenced 'src' packet natively in odp_packet_concat() below.
449 */
450 return concat_packet_with_ref(first_pkt, second_pkt);
451 }
452
453 odp_event_t odp_event_first = event_em2odp(*first_pkt);
454 odp_event_t odp_event_second = event_em2odp(second_pkt);
455
456 if (unlikely(EM_CHECK_LEVEL >= 3 &&
457 (!is_odp_packet(odp_event_first) ||
458 !is_odp_packet(odp_event_second)))) {
459 (void)INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_PACKET_CONCAT,
460 "first_pkt and/or second_pkt not a packet");
461 return -1;
462 }
463
464 const bool esv_ena = esv_enabled();
465 event_hdr_t *ev_hdr_first;
466 event_hdr_t *ev_hdr_second;
467
468 /* Save event hdl for later checking if it has changed */
469 evhdl_t ev_hdl_original = {.event = *first_pkt};
470
471 odp_packet_t odp_pkt_first = odp_packet_from_event(odp_event_first);
472 odp_packet_t odp_pkt_second = odp_packet_from_event(odp_event_second);
473
474 /* Mark pkts as free, since ODP might free it */
475 if (esv_ena) {
476 ev_hdr_first = odp_packet_user_area(odp_pkt_first);
477 ev_hdr_second = odp_packet_user_area(odp_pkt_second);
478
479 evstate_free(*first_pkt, ev_hdr_first, EVSTATE__MARK_FREE);
480 evstate_free(second_pkt, ev_hdr_second, EVSTATE__MARK_FREE);
481 }
482
483 int ret = odp_packet_concat(&odp_pkt_first, odp_pkt_second);
484
485 if (unlikely(ret < 0)) {
486 /* If odp_packet_concat() fails, pkt handles will not change */
487 if (esv_ena) {
488 evstate_unmark_free(*first_pkt, ev_hdr_first, EVSTATE__UNMARK_FREE);
489 evstate_unmark_free(second_pkt, ev_hdr_second, EVSTATE__UNMARK_FREE);
490 }
491 return -1;
492 }
493 ev_hdr_first = odp_packet_user_area(odp_pkt_first);
494 /* Check if the event handle has changed, and update it and event hdr */
495 evhdl_t ev_hdl_updated = {.event = event_odp2em(odp_packet_to_event(odp_pkt_first))};
496
497 *first_pkt = check_update_event(ev_hdl_original, ev_hdl_updated, ev_hdr_first);
498 /* Unmark free resulted first_pkt */
499 if (esv_ena)
500 evstate_unmark_free(*first_pkt, ev_hdr_first, EVSTATE__UNMARK_FREE);
501
502 if (ret == 0)
503 return 0;
504
505 return 1;
506}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
#define USER_FLAG_SET
#define EM_CHECK_LEVEL
#define PRI_POOL
#define EM_EVENT_GROUP_UNDEF
#define EM_OK
uint32_t em_status_t
@ EM_ERR_BAD_ID
@ EM_ERR_BAD_ARG
@ EM_ERR_LIB_FAILED
void em_free(em_event_t event)
void * em_packet_pull_head(em_event_t pktev, uint32_t len)
Pull in the beginning of the packet from the headroom.
void * em_packet_pull_tail(em_event_t pktev, uint32_t len)
void * em_packet_push_head(em_event_t pktev, uint32_t len)
Push out the beginning of the packet into the headroom.
void * em_packet_pointer(em_event_t pktev)
void * em_packet_pointer_and_size(em_event_t pktev, uint32_t *size)
Get the packet event data pointer as well as the packet size.
em_status_t em_packet_reset(em_event_t pktev, uint32_t size)
uint32_t em_packet_headroom(em_event_t pktev)
Packet event headroom length.
int em_packet_concat(em_event_t *first_pkt, em_event_t second_pkt)
Concatenate packet events.
uint32_t em_packet_size(em_event_t pktev)
Get the packet size.
void * em_packet_push_tail(em_event_t pktev, uint32_t len)
Push out the end of the packet into the tailroom.
void * em_packet_resize(em_event_t pktev, uint32_t size)
Resize a packet event.
uint32_t em_packet_tailroom(em_event_t pktev)
Packet event tailroom length.
em_event_t event
ev_hdr_user_area_t user_area
uint32_t event_size
em_event_group_t egrp
uint32_t align_offset