Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2016 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <stdio.h>
7 : :
8 : : #include <rte_common.h>
9 : : #include <rte_mbuf.h>
10 : : #include <rte_malloc.h>
11 : : #include <rte_string_fns.h>
12 : :
13 : : #include "rte_pipeline.h"
14 : :
15 [ - + ]: 251 : RTE_LOG_REGISTER_DEFAULT(pipeline_logtype, INFO);
16 : : #define RTE_LOGTYPE_PIPELINE pipeline_logtype
17 : :
18 : : #define PIPELINE_LOG(level, ...) \
19 : : RTE_LOG_LINE(level, PIPELINE, "" __VA_ARGS__)
20 : :
21 : : #define RTE_TABLE_INVALID UINT32_MAX
22 : :
23 : : #ifdef RTE_PIPELINE_STATS_COLLECT
24 : :
25 : : #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask) \
26 : : __extension__ ({ (p)->n_pkts_ah_drop = rte_popcount64(mask); })
27 : :
28 : : #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter) \
29 : : __extension__ ({ (counter) += (p)->n_pkts_ah_drop; (p)->n_pkts_ah_drop = 0; })
30 : :
31 : : #define RTE_PIPELINE_STATS_TABLE_DROP0(p) \
32 : : __extension__ ({ (p)->pkts_drop_mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; })
33 : :
34 : : #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter) \
35 : : __extension__ ({ \
36 : : uint64_t mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; \
37 : : mask ^= (p)->pkts_drop_mask; \
38 : : (counter) += rte_popcount64(mask); \
39 : : })
40 : :
41 : : #else
42 : :
43 : : #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)
44 : : #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)
45 : : #define RTE_PIPELINE_STATS_TABLE_DROP0(p)
46 : : #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)
47 : :
48 : : #endif
49 : :
50 : : struct rte_port_in {
51 : : /* Input parameters */
52 : : struct rte_port_in_ops ops;
53 : : rte_pipeline_port_in_action_handler f_action;
54 : : void *arg_ah;
55 : : uint32_t burst_size;
56 : :
57 : : /* The table to which this port is connected */
58 : : uint32_t table_id;
59 : :
60 : : /* Handle to low-level port */
61 : : void *h_port;
62 : :
63 : : /* List of enabled ports */
64 : : struct rte_port_in *next;
65 : :
66 : : /* Statistics */
67 : : uint64_t n_pkts_dropped_by_ah;
68 : : };
69 : :
70 : : struct rte_port_out {
71 : : /* Input parameters */
72 : : struct rte_port_out_ops ops;
73 : : rte_pipeline_port_out_action_handler f_action;
74 : : void *arg_ah;
75 : :
76 : : /* Handle to low-level port */
77 : : void *h_port;
78 : :
79 : : /* Statistics */
80 : : uint64_t n_pkts_dropped_by_ah;
81 : : };
82 : :
83 : : struct rte_table {
84 : : /* Input parameters */
85 : : struct rte_table_ops ops;
86 : : rte_pipeline_table_action_handler_hit f_action_hit;
87 : : rte_pipeline_table_action_handler_miss f_action_miss;
88 : : void *arg_ah;
89 : : struct rte_pipeline_table_entry *default_entry;
90 : : uint32_t entry_size;
91 : :
92 : : uint32_t table_next_id;
93 : : uint32_t table_next_id_valid;
94 : :
95 : : /* Handle to the low-level table object */
96 : : void *h_table;
97 : :
98 : : /* Statistics */
99 : : uint64_t n_pkts_dropped_by_lkp_hit_ah;
100 : : uint64_t n_pkts_dropped_by_lkp_miss_ah;
101 : : uint64_t n_pkts_dropped_lkp_hit;
102 : : uint64_t n_pkts_dropped_lkp_miss;
103 : : };
104 : :
105 : : #define RTE_PIPELINE_MAX_NAME_SZ 124
106 : :
107 : : struct __rte_cache_aligned rte_pipeline {
108 : : /* Input parameters */
109 : : char name[RTE_PIPELINE_MAX_NAME_SZ];
110 : : int socket_id;
111 : : uint32_t offset_port_id;
112 : :
113 : : /* Internal tables */
114 : : struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
115 : : struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
116 : : struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
117 : :
118 : : /* Occupancy of internal tables */
119 : : uint32_t num_ports_in;
120 : : uint32_t num_ports_out;
121 : : uint32_t num_tables;
122 : :
123 : : /* List of enabled ports */
124 : : uint64_t enabled_port_in_mask;
125 : : struct rte_port_in *port_in_next;
126 : :
127 : : /* Pipeline run structures */
128 : : struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
129 : : struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
130 : : uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
131 : : uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
132 : : uint64_t pkts_mask;
133 : : uint64_t n_pkts_ah_drop;
134 : : uint64_t pkts_drop_mask;
135 : : };
136 : :
137 : : static inline uint32_t
138 : : rte_mask_get_next(uint64_t mask, uint32_t pos)
139 : : {
140 : 25 : uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
141 : 25 : (mask >> ((pos + 1) & 0x3F));
142 : 25 : return (rte_ctz64(mask_rot) - (63 - pos)) & 0x3F;
143 : : }
144 : :
145 : : static inline uint32_t
146 : : rte_mask_get_prev(uint64_t mask, uint32_t pos)
147 : : {
148 [ # # ]: 0 : uint64_t mask_rot = (mask >> (pos & 0x3F)) |
149 : : (mask << ((64 - pos) & 0x3F));
150 [ - - + + ]: 25 : return ((63 - rte_clz64(mask_rot)) + pos) & 0x3F;
151 : : }
152 : :
153 : : static void
154 : : rte_pipeline_table_free(struct rte_table *table);
155 : :
156 : : static void
157 : : rte_pipeline_port_in_free(struct rte_port_in *port);
158 : :
159 : : static void
160 : : rte_pipeline_port_out_free(struct rte_port_out *port);
161 : :
162 : : /*
163 : : * Pipeline
164 : : */
165 : : static int
166 : 48 : rte_pipeline_check_params(struct rte_pipeline_params *params)
167 : : {
168 [ + + ]: 48 : if (params == NULL) {
169 : 1 : PIPELINE_LOG(ERR,
170 : : "%s: Incorrect value for parameter params", __func__);
171 : 1 : return -EINVAL;
172 : : }
173 : :
174 : : /* name */
175 [ + + ]: 47 : if (params->name == NULL) {
176 : 1 : PIPELINE_LOG(ERR,
177 : : "%s: Incorrect value for parameter name", __func__);
178 : 1 : return -EINVAL;
179 : : }
180 : :
181 : : /* socket */
182 [ + + ]: 46 : if (params->socket_id < 0) {
183 : 1 : PIPELINE_LOG(ERR,
184 : : "%s: Incorrect value for parameter socket_id",
185 : : __func__);
186 : 1 : return -EINVAL;
187 : : }
188 : :
189 : : return 0;
190 : : }
191 : :
192 : : struct rte_pipeline *
193 : 48 : rte_pipeline_create(struct rte_pipeline_params *params)
194 : : {
195 : : struct rte_pipeline *p;
196 : : int status;
197 : :
198 : : /* Check input parameters */
199 : 48 : status = rte_pipeline_check_params(params);
200 [ + + ]: 48 : if (status != 0) {
201 : 3 : PIPELINE_LOG(ERR,
202 : : "%s: Pipeline params check failed (%d)",
203 : : __func__, status);
204 : 3 : return NULL;
205 : : }
206 : :
207 : : /* Allocate memory for the pipeline on requested socket */
208 : 45 : p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
209 : : RTE_CACHE_LINE_SIZE, params->socket_id);
210 : :
211 [ - + ]: 45 : if (p == NULL) {
212 : 0 : PIPELINE_LOG(ERR,
213 : : "%s: Pipeline memory allocation failed", __func__);
214 : 0 : return NULL;
215 : : }
216 : :
217 : : /* Save input parameters */
218 : 45 : strlcpy(p->name, params->name, RTE_PIPELINE_MAX_NAME_SZ);
219 : 45 : p->socket_id = params->socket_id;
220 : 45 : p->offset_port_id = params->offset_port_id;
221 : :
222 : : /* Initialize pipeline internal data structure */
223 : 45 : p->num_ports_in = 0;
224 : 45 : p->num_ports_out = 0;
225 : 45 : p->num_tables = 0;
226 : 45 : p->enabled_port_in_mask = 0;
227 : 45 : p->port_in_next = NULL;
228 : 45 : p->pkts_mask = 0;
229 : 45 : p->n_pkts_ah_drop = 0;
230 : :
231 : 45 : return p;
232 : : }
233 : :
234 : : int
235 : 45 : rte_pipeline_free(struct rte_pipeline *p)
236 : : {
237 : : uint32_t i;
238 : :
239 : : /* Check input parameters */
240 [ - + ]: 45 : if (p == NULL) {
241 : 0 : PIPELINE_LOG(ERR,
242 : : "%s: rte_pipeline parameter is NULL", __func__);
243 : 0 : return -EINVAL;
244 : : }
245 : :
246 : : /* Free input ports */
247 [ + + ]: 91 : for (i = 0; i < p->num_ports_in; i++) {
248 : : struct rte_port_in *port = &p->ports_in[i];
249 : :
250 : : rte_pipeline_port_in_free(port);
251 : : }
252 : :
253 : : /* Free tables */
254 [ + + ]: 78 : for (i = 0; i < p->num_tables; i++) {
255 : 33 : struct rte_table *table = &p->tables[i];
256 : :
257 : 33 : rte_pipeline_table_free(table);
258 : : }
259 : :
260 : : /* Free output ports */
261 [ + + ]: 87 : for (i = 0; i < p->num_ports_out; i++) {
262 : : struct rte_port_out *port = &p->ports_out[i];
263 : :
264 : : rte_pipeline_port_out_free(port);
265 : : }
266 : :
267 : : /* Free pipeline memory */
268 : 45 : rte_free(p);
269 : :
270 : 45 : return 0;
271 : : }
272 : :
273 : : /*
274 : : * Table
275 : : */
276 : : static int
277 : 50 : rte_table_check_params(struct rte_pipeline *p,
278 : : struct rte_pipeline_table_params *params,
279 : : uint32_t *table_id)
280 : : {
281 [ - + ]: 50 : if (p == NULL) {
282 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter is NULL",
283 : : __func__);
284 : 0 : return -EINVAL;
285 : : }
286 [ - + ]: 50 : if (params == NULL) {
287 : 0 : PIPELINE_LOG(ERR, "%s: params parameter is NULL",
288 : : __func__);
289 : 0 : return -EINVAL;
290 : : }
291 [ - + ]: 50 : if (table_id == NULL) {
292 : 0 : PIPELINE_LOG(ERR, "%s: table_id parameter is NULL",
293 : : __func__);
294 : 0 : return -EINVAL;
295 : : }
296 : :
297 : : /* ops */
298 [ - + ]: 50 : if (params->ops == NULL) {
299 : 0 : PIPELINE_LOG(ERR, "%s: params->ops is NULL",
300 : : __func__);
301 : 0 : return -EINVAL;
302 : : }
303 : :
304 [ - + ]: 50 : if (params->ops->f_create == NULL) {
305 : 0 : PIPELINE_LOG(ERR,
306 : : "%s: f_create function pointer is NULL", __func__);
307 : 0 : return -EINVAL;
308 : : }
309 : :
310 [ - + ]: 50 : if (params->ops->f_lookup == NULL) {
311 : 0 : PIPELINE_LOG(ERR,
312 : : "%s: f_lookup function pointer is NULL", __func__);
313 : 0 : return -EINVAL;
314 : : }
315 : :
316 : : /* De we have room for one more table? */
317 [ - + ]: 50 : if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
318 : 0 : PIPELINE_LOG(ERR,
319 : : "%s: Incorrect value for num_tables parameter",
320 : : __func__);
321 : 0 : return -EINVAL;
322 : : }
323 : :
324 : : return 0;
325 : : }
326 : :
327 : : int
328 : 50 : rte_pipeline_table_create(struct rte_pipeline *p,
329 : : struct rte_pipeline_table_params *params,
330 : : uint32_t *table_id)
331 : : {
332 : : struct rte_table *table;
333 : : struct rte_pipeline_table_entry *default_entry;
334 : : void *h_table;
335 : : uint32_t entry_size, id;
336 : : int status;
337 : :
338 : : /* Check input arguments */
339 : 50 : status = rte_table_check_params(p, params, table_id);
340 [ + - ]: 50 : if (status != 0)
341 : : return status;
342 : :
343 : 50 : id = p->num_tables;
344 : : table = &p->tables[id];
345 : :
346 : : /* Allocate space for the default table entry */
347 : 50 : entry_size = sizeof(struct rte_pipeline_table_entry) +
348 : 50 : params->action_data_size;
349 : 50 : default_entry = rte_zmalloc_socket(
350 : : "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
351 [ - + ]: 50 : if (default_entry == NULL) {
352 : 0 : PIPELINE_LOG(ERR,
353 : : "%s: Failed to allocate default entry", __func__);
354 : 0 : return -EINVAL;
355 : : }
356 : :
357 : : /* Create the table */
358 : 50 : h_table = params->ops->f_create(params->arg_create, p->socket_id,
359 : : entry_size);
360 [ + + ]: 50 : if (h_table == NULL) {
361 : 17 : rte_free(default_entry);
362 : 17 : PIPELINE_LOG(ERR, "%s: Table creation failed", __func__);
363 : 17 : return -EINVAL;
364 : : }
365 : :
366 : : /* Commit current table to the pipeline */
367 : 33 : p->num_tables++;
368 : 33 : *table_id = id;
369 : :
370 : : /* Save input parameters */
371 : 33 : memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
372 : 33 : table->f_action_hit = params->f_action_hit;
373 : 33 : table->f_action_miss = params->f_action_miss;
374 : 33 : table->arg_ah = params->arg_ah;
375 : 33 : table->entry_size = entry_size;
376 : :
377 : : /* Clear the lookup miss actions (to be set later through API) */
378 : 33 : table->default_entry = default_entry;
379 : 33 : table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
380 : :
381 : : /* Initialize table internal data structure */
382 : 33 : table->h_table = h_table;
383 : 33 : table->table_next_id = 0;
384 : 33 : table->table_next_id_valid = 0;
385 : :
386 : 33 : return 0;
387 : : }
388 : :
389 : : void
390 : 33 : rte_pipeline_table_free(struct rte_table *table)
391 : : {
392 [ + + ]: 33 : if (table->ops.f_free != NULL)
393 : 15 : table->ops.f_free(table->h_table);
394 : :
395 : 33 : rte_free(table->default_entry);
396 : 33 : }
397 : :
398 : : int
399 : 40 : rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
400 : : uint32_t table_id,
401 : : struct rte_pipeline_table_entry *default_entry,
402 : : struct rte_pipeline_table_entry **default_entry_ptr)
403 : : {
404 : : struct rte_table *table;
405 : :
406 : : /* Check input arguments */
407 [ - + ]: 40 : if (p == NULL) {
408 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter is NULL",
409 : : __func__);
410 : 0 : return -EINVAL;
411 : : }
412 : :
413 [ - + ]: 40 : if (default_entry == NULL) {
414 : 0 : PIPELINE_LOG(ERR,
415 : : "%s: default_entry parameter is NULL", __func__);
416 : 0 : return -EINVAL;
417 : : }
418 : :
419 [ - + ]: 40 : if (table_id >= p->num_tables) {
420 : 0 : PIPELINE_LOG(ERR,
421 : : "%s: table_id %d out of range", __func__, table_id);
422 : 0 : return -EINVAL;
423 : : }
424 : :
425 : : table = &p->tables[table_id];
426 : :
427 [ + + ]: 40 : if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
428 [ - + ]: 4 : table->table_next_id_valid &&
429 [ # # ]: 0 : (default_entry->table_id != table->table_next_id)) {
430 : 0 : PIPELINE_LOG(ERR,
431 : : "%s: Tree-like topologies not allowed", __func__);
432 : 0 : return -EINVAL;
433 : : }
434 : :
435 : : /* Set the lookup miss actions */
436 [ + + ]: 40 : if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
437 [ + - ]: 4 : (table->table_next_id_valid == 0)) {
438 : 4 : table->table_next_id = default_entry->table_id;
439 : 4 : table->table_next_id_valid = 1;
440 : : }
441 : :
442 : 40 : memcpy(table->default_entry, default_entry, table->entry_size);
443 : :
444 : 40 : *default_entry_ptr = table->default_entry;
445 : 40 : return 0;
446 : : }
447 : :
448 : : int
449 : 0 : rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
450 : : uint32_t table_id,
451 : : struct rte_pipeline_table_entry *entry)
452 : : {
453 : : struct rte_table *table;
454 : :
455 : : /* Check input arguments */
456 [ # # ]: 0 : if (p == NULL) {
457 : 0 : PIPELINE_LOG(ERR,
458 : : "%s: pipeline parameter is NULL", __func__);
459 : 0 : return -EINVAL;
460 : : }
461 : :
462 [ # # ]: 0 : if (table_id >= p->num_tables) {
463 : 0 : PIPELINE_LOG(ERR,
464 : : "%s: table_id %d out of range", __func__, table_id);
465 : 0 : return -EINVAL;
466 : : }
467 : :
468 : : table = &p->tables[table_id];
469 : :
470 : : /* Save the current contents of the default entry */
471 [ # # ]: 0 : if (entry)
472 : 0 : memcpy(entry, table->default_entry, table->entry_size);
473 : :
474 : : /* Clear the lookup miss actions */
475 : 0 : memset(table->default_entry, 0, table->entry_size);
476 : 0 : table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
477 : :
478 : 0 : return 0;
479 : : }
480 : :
481 : : int
482 : 42 : rte_pipeline_table_entry_add(struct rte_pipeline *p,
483 : : uint32_t table_id,
484 : : void *key,
485 : : struct rte_pipeline_table_entry *entry,
486 : : int *key_found,
487 : : struct rte_pipeline_table_entry **entry_ptr)
488 : : {
489 : : struct rte_table *table;
490 : :
491 : : /* Check input arguments */
492 [ - + ]: 42 : if (p == NULL) {
493 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter is NULL",
494 : : __func__);
495 : 0 : return -EINVAL;
496 : : }
497 : :
498 [ - + ]: 42 : if (key == NULL) {
499 : 0 : PIPELINE_LOG(ERR, "%s: key parameter is NULL", __func__);
500 : 0 : return -EINVAL;
501 : : }
502 : :
503 [ - + ]: 42 : if (entry == NULL) {
504 : 0 : PIPELINE_LOG(ERR, "%s: entry parameter is NULL",
505 : : __func__);
506 : 0 : return -EINVAL;
507 : : }
508 : :
509 [ - + ]: 42 : if (table_id >= p->num_tables) {
510 : 0 : PIPELINE_LOG(ERR,
511 : : "%s: table_id %d out of range", __func__, table_id);
512 : 0 : return -EINVAL;
513 : : }
514 : :
515 : : table = &p->tables[table_id];
516 : :
517 [ - + ]: 42 : if (table->ops.f_add == NULL) {
518 : 0 : PIPELINE_LOG(ERR, "%s: f_add function pointer NULL",
519 : : __func__);
520 : 0 : return -EINVAL;
521 : : }
522 : :
523 [ - + ]: 42 : if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
524 [ # # ]: 0 : table->table_next_id_valid &&
525 [ # # ]: 0 : (entry->table_id != table->table_next_id)) {
526 : 0 : PIPELINE_LOG(ERR,
527 : : "%s: Tree-like topologies not allowed", __func__);
528 : 0 : return -EINVAL;
529 : : }
530 : :
531 : : /* Add entry */
532 [ - + ]: 42 : if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
533 [ # # ]: 0 : (table->table_next_id_valid == 0)) {
534 : 0 : table->table_next_id = entry->table_id;
535 : 0 : table->table_next_id_valid = 1;
536 : : }
537 : :
538 : 42 : return (table->ops.f_add)(table->h_table, key, (void *) entry,
539 : : key_found, (void **) entry_ptr);
540 : : }
541 : :
542 : : int
543 : 13 : rte_pipeline_table_entry_delete(struct rte_pipeline *p,
544 : : uint32_t table_id,
545 : : void *key,
546 : : int *key_found,
547 : : struct rte_pipeline_table_entry *entry)
548 : : {
549 : : struct rte_table *table;
550 : :
551 : : /* Check input arguments */
552 [ - + ]: 13 : if (p == NULL) {
553 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
554 : : __func__);
555 : 0 : return -EINVAL;
556 : : }
557 : :
558 [ - + ]: 13 : if (key == NULL) {
559 : 0 : PIPELINE_LOG(ERR, "%s: key parameter is NULL",
560 : : __func__);
561 : 0 : return -EINVAL;
562 : : }
563 : :
564 [ - + ]: 13 : if (table_id >= p->num_tables) {
565 : 0 : PIPELINE_LOG(ERR,
566 : : "%s: table_id %d out of range", __func__, table_id);
567 : 0 : return -EINVAL;
568 : : }
569 : :
570 : : table = &p->tables[table_id];
571 : :
572 [ - + ]: 13 : if (table->ops.f_delete == NULL) {
573 : 0 : PIPELINE_LOG(ERR,
574 : : "%s: f_delete function pointer NULL", __func__);
575 : 0 : return -EINVAL;
576 : : }
577 : :
578 : 13 : return (table->ops.f_delete)(table->h_table, key, key_found, entry);
579 : : }
580 : :
581 : 2 : int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p,
582 : : uint32_t table_id,
583 : : void **keys,
584 : : struct rte_pipeline_table_entry **entries,
585 : : uint32_t n_keys,
586 : : int *key_found,
587 : : struct rte_pipeline_table_entry **entries_ptr)
588 : : {
589 : : struct rte_table *table;
590 : : uint32_t i;
591 : :
592 : : /* Check input arguments */
593 [ - + ]: 2 : if (p == NULL) {
594 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter is NULL",
595 : : __func__);
596 : 0 : return -EINVAL;
597 : : }
598 : :
599 [ - + ]: 2 : if (keys == NULL) {
600 : 0 : PIPELINE_LOG(ERR, "%s: keys parameter is NULL", __func__);
601 : 0 : return -EINVAL;
602 : : }
603 : :
604 [ - + ]: 2 : if (entries == NULL) {
605 : 0 : PIPELINE_LOG(ERR, "%s: entries parameter is NULL",
606 : : __func__);
607 : 0 : return -EINVAL;
608 : : }
609 : :
610 [ - + ]: 2 : if (table_id >= p->num_tables) {
611 : 0 : PIPELINE_LOG(ERR,
612 : : "%s: table_id %d out of range", __func__, table_id);
613 : 0 : return -EINVAL;
614 : : }
615 : :
616 : : table = &p->tables[table_id];
617 : :
618 [ - + ]: 2 : if (table->ops.f_add_bulk == NULL) {
619 : 0 : PIPELINE_LOG(ERR, "%s: f_add_bulk function pointer NULL",
620 : : __func__);
621 : 0 : return -EINVAL;
622 : : }
623 : :
624 [ + + ]: 12 : for (i = 0; i < n_keys; i++) {
625 [ - + ]: 10 : if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
626 [ # # ]: 0 : table->table_next_id_valid &&
627 [ # # ]: 0 : (entries[i]->table_id != table->table_next_id)) {
628 : 0 : PIPELINE_LOG(ERR,
629 : : "%s: Tree-like topologies not allowed", __func__);
630 : 0 : return -EINVAL;
631 : : }
632 : : }
633 : :
634 : : /* Add entry */
635 [ + + ]: 12 : for (i = 0; i < n_keys; i++) {
636 [ - + ]: 10 : if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
637 [ # # ]: 0 : (table->table_next_id_valid == 0)) {
638 : 0 : table->table_next_id = entries[i]->table_id;
639 : 0 : table->table_next_id_valid = 1;
640 : : }
641 : : }
642 : :
643 : 2 : return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries,
644 : : n_keys, key_found, (void **) entries_ptr);
645 : : }
646 : :
647 : 2 : int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p,
648 : : uint32_t table_id,
649 : : void **keys,
650 : : uint32_t n_keys,
651 : : int *key_found,
652 : : struct rte_pipeline_table_entry **entries)
653 : : {
654 : : struct rte_table *table;
655 : :
656 : : /* Check input arguments */
657 [ - + ]: 2 : if (p == NULL) {
658 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
659 : : __func__);
660 : 0 : return -EINVAL;
661 : : }
662 : :
663 [ - + ]: 2 : if (keys == NULL) {
664 : 0 : PIPELINE_LOG(ERR, "%s: key parameter is NULL",
665 : : __func__);
666 : 0 : return -EINVAL;
667 : : }
668 : :
669 [ - + ]: 2 : if (table_id >= p->num_tables) {
670 : 0 : PIPELINE_LOG(ERR,
671 : : "%s: table_id %d out of range", __func__, table_id);
672 : 0 : return -EINVAL;
673 : : }
674 : :
675 : : table = &p->tables[table_id];
676 : :
677 [ - + ]: 2 : if (table->ops.f_delete_bulk == NULL) {
678 : 0 : PIPELINE_LOG(ERR,
679 : : "%s: f_delete function pointer NULL", __func__);
680 : 0 : return -EINVAL;
681 : : }
682 : :
683 : 2 : return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found,
684 : : (void **) entries);
685 : : }
686 : :
687 : : /*
688 : : * Port
689 : : */
690 : : static int
691 : 46 : rte_pipeline_port_in_check_params(struct rte_pipeline *p,
692 : : struct rte_pipeline_port_in_params *params,
693 : : uint32_t *port_id)
694 : : {
695 [ - + ]: 46 : if (p == NULL) {
696 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
697 : : __func__);
698 : 0 : return -EINVAL;
699 : : }
700 [ - + ]: 46 : if (params == NULL) {
701 : 0 : PIPELINE_LOG(ERR, "%s: params parameter NULL", __func__);
702 : 0 : return -EINVAL;
703 : : }
704 [ - + ]: 46 : if (port_id == NULL) {
705 : 0 : PIPELINE_LOG(ERR, "%s: port_id parameter NULL",
706 : : __func__);
707 : 0 : return -EINVAL;
708 : : }
709 : :
710 : : /* ops */
711 [ - + ]: 46 : if (params->ops == NULL) {
712 : 0 : PIPELINE_LOG(ERR, "%s: params->ops parameter NULL",
713 : : __func__);
714 : 0 : return -EINVAL;
715 : : }
716 : :
717 [ - + ]: 46 : if (params->ops->f_create == NULL) {
718 : 0 : PIPELINE_LOG(ERR,
719 : : "%s: f_create function pointer NULL", __func__);
720 : 0 : return -EINVAL;
721 : : }
722 : :
723 [ - + ]: 46 : if (params->ops->f_rx == NULL) {
724 : 0 : PIPELINE_LOG(ERR, "%s: f_rx function pointer NULL",
725 : : __func__);
726 : 0 : return -EINVAL;
727 : : }
728 : :
729 : : /* burst_size */
730 [ - + ]: 46 : if ((params->burst_size == 0) ||
731 : : (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
732 : 0 : PIPELINE_LOG(ERR, "%s: invalid value for burst_size",
733 : : __func__);
734 : 0 : return -EINVAL;
735 : : }
736 : :
737 : : /* Do we have room for one more port? */
738 [ - + ]: 46 : if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
739 : 0 : PIPELINE_LOG(ERR,
740 : : "%s: invalid value for num_ports_in", __func__);
741 : 0 : return -EINVAL;
742 : : }
743 : :
744 : : return 0;
745 : : }
746 : :
747 : : static int
748 : 42 : rte_pipeline_port_out_check_params(struct rte_pipeline *p,
749 : : struct rte_pipeline_port_out_params *params,
750 : : uint32_t *port_id)
751 : : {
752 [ - + ]: 42 : if (p == NULL) {
753 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
754 : : __func__);
755 : 0 : return -EINVAL;
756 : : }
757 : :
758 [ - + ]: 42 : if (params == NULL) {
759 : 0 : PIPELINE_LOG(ERR, "%s: params parameter NULL", __func__);
760 : 0 : return -EINVAL;
761 : : }
762 : :
763 [ - + ]: 42 : if (port_id == NULL) {
764 : 0 : PIPELINE_LOG(ERR, "%s: port_id parameter NULL",
765 : : __func__);
766 : 0 : return -EINVAL;
767 : : }
768 : :
769 : : /* ops */
770 [ - + ]: 42 : if (params->ops == NULL) {
771 : 0 : PIPELINE_LOG(ERR, "%s: params->ops parameter NULL",
772 : : __func__);
773 : 0 : return -EINVAL;
774 : : }
775 : :
776 [ - + ]: 42 : if (params->ops->f_create == NULL) {
777 : 0 : PIPELINE_LOG(ERR,
778 : : "%s: f_create function pointer NULL", __func__);
779 : 0 : return -EINVAL;
780 : : }
781 : :
782 [ - + ]: 42 : if (params->ops->f_tx == NULL) {
783 : 0 : PIPELINE_LOG(ERR,
784 : : "%s: f_tx function pointer NULL", __func__);
785 : 0 : return -EINVAL;
786 : : }
787 : :
788 [ - + ]: 42 : if (params->ops->f_tx_bulk == NULL) {
789 : 0 : PIPELINE_LOG(ERR,
790 : : "%s: f_tx_bulk function pointer NULL", __func__);
791 : 0 : return -EINVAL;
792 : : }
793 : :
794 : : /* Do we have room for one more port? */
795 [ - + ]: 42 : if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
796 : 0 : PIPELINE_LOG(ERR,
797 : : "%s: invalid value for num_ports_out", __func__);
798 : 0 : return -EINVAL;
799 : : }
800 : :
801 : : return 0;
802 : : }
803 : :
804 : : int
805 : 46 : rte_pipeline_port_in_create(struct rte_pipeline *p,
806 : : struct rte_pipeline_port_in_params *params,
807 : : uint32_t *port_id)
808 : : {
809 : : struct rte_port_in *port;
810 : : void *h_port;
811 : : uint32_t id;
812 : : int status;
813 : :
814 : : /* Check input arguments */
815 : 46 : status = rte_pipeline_port_in_check_params(p, params, port_id);
816 [ + - ]: 46 : if (status != 0)
817 : : return status;
818 : :
819 : 46 : id = p->num_ports_in;
820 : : port = &p->ports_in[id];
821 : :
822 : : /* Create the port */
823 : 46 : h_port = params->ops->f_create(params->arg_create, p->socket_id);
824 [ - + ]: 46 : if (h_port == NULL) {
825 : 0 : PIPELINE_LOG(ERR, "%s: Port creation failed", __func__);
826 : 0 : return -EINVAL;
827 : : }
828 : :
829 : : /* Commit current table to the pipeline */
830 : 46 : p->num_ports_in++;
831 : 46 : *port_id = id;
832 : :
833 : : /* Save input parameters */
834 : 46 : memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
835 : 46 : port->f_action = params->f_action;
836 : 46 : port->arg_ah = params->arg_ah;
837 : 46 : port->burst_size = params->burst_size;
838 : :
839 : : /* Initialize port internal data structure */
840 : 46 : port->table_id = RTE_TABLE_INVALID;
841 : 46 : port->h_port = h_port;
842 : 46 : port->next = NULL;
843 : :
844 : 46 : return 0;
845 : : }
846 : :
847 : : void
848 : : rte_pipeline_port_in_free(struct rte_port_in *port)
849 : : {
850 [ + - ]: 46 : if (port->ops.f_free != NULL)
851 : 46 : port->ops.f_free(port->h_port);
852 : : }
853 : :
854 : : int
855 : 42 : rte_pipeline_port_out_create(struct rte_pipeline *p,
856 : : struct rte_pipeline_port_out_params *params,
857 : : uint32_t *port_id)
858 : : {
859 : : struct rte_port_out *port;
860 : : void *h_port;
861 : : uint32_t id;
862 : : int status;
863 : :
864 : : /* Check input arguments */
865 : 42 : status = rte_pipeline_port_out_check_params(p, params, port_id);
866 [ + - ]: 42 : if (status != 0)
867 : : return status;
868 : :
869 : 42 : id = p->num_ports_out;
870 : : port = &p->ports_out[id];
871 : :
872 : : /* Create the port */
873 : 42 : h_port = params->ops->f_create(params->arg_create, p->socket_id);
874 [ - + ]: 42 : if (h_port == NULL) {
875 : 0 : PIPELINE_LOG(ERR, "%s: Port creation failed", __func__);
876 : 0 : return -EINVAL;
877 : : }
878 : :
879 : : /* Commit current table to the pipeline */
880 : 42 : p->num_ports_out++;
881 : 42 : *port_id = id;
882 : :
883 : : /* Save input parameters */
884 : 42 : memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
885 : 42 : port->f_action = params->f_action;
886 : 42 : port->arg_ah = params->arg_ah;
887 : :
888 : : /* Initialize port internal data structure */
889 : 42 : port->h_port = h_port;
890 : :
891 : 42 : return 0;
892 : : }
893 : :
894 : : void
895 : : rte_pipeline_port_out_free(struct rte_port_out *port)
896 : : {
897 [ + - ]: 42 : if (port->ops.f_free != NULL)
898 : 42 : port->ops.f_free(port->h_port);
899 : : }
900 : :
901 : : int
902 : 25 : rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
903 : : uint32_t port_id,
904 : : uint32_t table_id)
905 : : {
906 : : struct rte_port_in *port;
907 : :
908 : : /* Check input arguments */
909 [ - + ]: 25 : if (p == NULL) {
910 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
911 : : __func__);
912 : 0 : return -EINVAL;
913 : : }
914 : :
915 [ - + ]: 25 : if (port_id >= p->num_ports_in) {
916 : 0 : PIPELINE_LOG(ERR,
917 : : "%s: port IN ID %u is out of range",
918 : : __func__, port_id);
919 : 0 : return -EINVAL;
920 : : }
921 : :
922 [ - + ]: 25 : if (table_id >= p->num_tables) {
923 : 0 : PIPELINE_LOG(ERR,
924 : : "%s: Table ID %u is out of range",
925 : : __func__, table_id);
926 : 0 : return -EINVAL;
927 : : }
928 : :
929 : : port = &p->ports_in[port_id];
930 : 25 : port->table_id = table_id;
931 : :
932 : 25 : return 0;
933 : : }
934 : :
935 : : int
936 : 25 : rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
937 : : {
938 : : struct rte_port_in *port, *port_prev, *port_next;
939 : : uint64_t port_mask;
940 : : uint32_t port_prev_id, port_next_id;
941 : :
942 : : /* Check input arguments */
943 [ - + ]: 25 : if (p == NULL) {
944 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
945 : : __func__);
946 : 0 : return -EINVAL;
947 : : }
948 : :
949 [ - + ]: 25 : if (port_id >= p->num_ports_in) {
950 : 0 : PIPELINE_LOG(ERR,
951 : : "%s: port IN ID %u is out of range",
952 : : __func__, port_id);
953 : 0 : return -EINVAL;
954 : : }
955 : :
956 : 25 : port = &p->ports_in[port_id];
957 : :
958 : : /* Return if current input port is already enabled */
959 : 25 : port_mask = 1LLU << port_id;
960 [ + - ]: 25 : if (p->enabled_port_in_mask & port_mask)
961 : : return 0;
962 : :
963 [ + + ]: 25 : p->enabled_port_in_mask |= port_mask;
964 : :
965 : : /* Add current input port to the pipeline chain of enabled ports */
966 : : port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
967 : : port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
968 : :
969 : : port_prev = &p->ports_in[port_prev_id];
970 : 25 : port_next = &p->ports_in[port_next_id];
971 : :
972 : 25 : port_prev->next = port;
973 : 25 : port->next = port_next;
974 : :
975 : : /* Check if list of enabled ports was previously empty */
976 [ + + ]: 25 : if (p->enabled_port_in_mask == port_mask)
977 : 17 : p->port_in_next = port;
978 : :
979 : : return 0;
980 : : }
981 : :
982 : : int
983 : 0 : rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
984 : : {
985 : : struct rte_port_in *port, *port_prev, *port_next;
986 : : uint64_t port_mask;
987 : : uint32_t port_prev_id, port_next_id;
988 : :
989 : : /* Check input arguments */
990 [ # # ]: 0 : if (p == NULL) {
991 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
992 : : __func__);
993 : 0 : return -EINVAL;
994 : : }
995 : :
996 [ # # ]: 0 : if (port_id >= p->num_ports_in) {
997 : 0 : PIPELINE_LOG(ERR, "%s: port IN ID %u is out of range",
998 : : __func__, port_id);
999 : 0 : return -EINVAL;
1000 : : }
1001 : :
1002 : 0 : port = &p->ports_in[port_id];
1003 : :
1004 : : /* Return if current input port is already disabled */
1005 : 0 : port_mask = 1LLU << port_id;
1006 [ # # ]: 0 : if ((p->enabled_port_in_mask & port_mask) == 0)
1007 : : return 0;
1008 : :
1009 : 0 : p->enabled_port_in_mask &= ~port_mask;
1010 : :
1011 : : /* Return if no other enabled ports */
1012 [ # # ]: 0 : if (p->enabled_port_in_mask == 0) {
1013 : 0 : p->port_in_next = NULL;
1014 : :
1015 : 0 : return 0;
1016 : : }
1017 : :
1018 : : /* Add current input port to the pipeline chain of enabled ports */
1019 : : port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
1020 : : port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1021 : :
1022 : : port_prev = &p->ports_in[port_prev_id];
1023 : 0 : port_next = &p->ports_in[port_next_id];
1024 : :
1025 : 0 : port_prev->next = port_next;
1026 : :
1027 : : /* Check if the port which has just been disabled is next to serve */
1028 [ # # ]: 0 : if (port == p->port_in_next)
1029 : 0 : p->port_in_next = port_next;
1030 : :
1031 : : return 0;
1032 : : }
1033 : :
1034 : : /*
1035 : : * Pipeline run-time
1036 : : */
1037 : : int
1038 : 18 : rte_pipeline_check(struct rte_pipeline *p)
1039 : : {
1040 : : uint32_t port_in_id;
1041 : :
1042 : : /* Check input arguments */
1043 [ + + ]: 18 : if (p == NULL) {
1044 : 1 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
1045 : : __func__);
1046 : 1 : return -EINVAL;
1047 : : }
1048 : :
1049 : : /* Check that pipeline has at least one input port, one table and one
1050 : : output port */
1051 [ - + ]: 17 : if (p->num_ports_in == 0) {
1052 : 0 : PIPELINE_LOG(ERR, "%s: must have at least 1 input port",
1053 : : __func__);
1054 : 0 : return -EINVAL;
1055 : : }
1056 [ - + ]: 17 : if (p->num_tables == 0) {
1057 : 0 : PIPELINE_LOG(ERR, "%s: must have at least 1 table",
1058 : : __func__);
1059 : 0 : return -EINVAL;
1060 : : }
1061 [ - + ]: 17 : if (p->num_ports_out == 0) {
1062 : 0 : PIPELINE_LOG(ERR, "%s: must have at least 1 output port",
1063 : : __func__);
1064 : 0 : return -EINVAL;
1065 : : }
1066 : :
1067 : : /* Check that all input ports are connected */
1068 [ + + ]: 42 : for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
1069 : : struct rte_port_in *port_in = &p->ports_in[port_in_id];
1070 : :
1071 [ - + ]: 25 : if (port_in->table_id == RTE_TABLE_INVALID) {
1072 : 0 : PIPELINE_LOG(ERR,
1073 : : "%s: Port IN ID %u is not connected",
1074 : : __func__, port_in_id);
1075 : 0 : return -EINVAL;
1076 : : }
1077 : : }
1078 : :
1079 : : return 0;
1080 : : }
1081 : :
1082 : : static inline void
1083 : 38 : rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1084 : : {
1085 : 38 : p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1086 : 38 : p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1087 : 38 : p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1088 : 38 : p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1089 : :
1090 [ + + ]: 38 : if ((pkts_mask & (pkts_mask + 1)) == 0) {
1091 : : uint64_t n_pkts = rte_popcount64(pkts_mask);
1092 : : uint32_t i;
1093 : :
1094 [ + + ]: 1170 : for (i = 0; i < n_pkts; i++) {
1095 : 1134 : uint64_t pkt_mask = 1LLU << i;
1096 : 1134 : uint32_t pos = p->entries[i]->action;
1097 : :
1098 : 1134 : p->action_mask1[pos] |= pkt_mask;
1099 : : }
1100 : : } else {
1101 : : uint32_t i;
1102 : :
1103 [ + + ]: 130 : for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1104 : 128 : uint64_t pkt_mask = 1LLU << i;
1105 : : uint32_t pos;
1106 : :
1107 [ + + ]: 128 : if ((pkt_mask & pkts_mask) == 0)
1108 : 118 : continue;
1109 : :
1110 : 10 : pos = p->entries[i]->action;
1111 : 10 : p->action_mask1[pos] |= pkt_mask;
1112 : : }
1113 : : }
1114 : 38 : }
1115 : :
1116 : : static inline void
1117 : 12 : rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1118 : : uint64_t pkts_mask, uint32_t port_id)
1119 : : {
1120 : : struct rte_port_out *port_out = &p->ports_out[port_id];
1121 : :
1122 : 12 : p->pkts_mask = pkts_mask;
1123 : :
1124 : : /* Output port user actions */
1125 [ - + ]: 12 : if (port_out->f_action != NULL) {
1126 : 0 : port_out->f_action(p, p->pkts, pkts_mask, port_out->arg_ah);
1127 : :
1128 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1129 : : port_out->n_pkts_dropped_by_ah);
1130 : : }
1131 : :
1132 : : /* Output port TX */
1133 [ + - ]: 12 : if (p->pkts_mask != 0)
1134 : 12 : port_out->ops.f_tx_bulk(port_out->h_port,
1135 : 12 : p->pkts,
1136 : : p->pkts_mask);
1137 : 12 : }
1138 : :
1139 : : static inline void
1140 : 70 : rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1141 : : {
1142 : 70 : p->pkts_mask = pkts_mask;
1143 : :
1144 [ + + ]: 70 : if ((pkts_mask & (pkts_mask + 1)) == 0) {
1145 : : uint64_t n_pkts = rte_popcount64(pkts_mask);
1146 : : uint32_t i;
1147 : :
1148 [ + + ]: 1202 : for (i = 0; i < n_pkts; i++) {
1149 : 1134 : struct rte_mbuf *pkt = p->pkts[i];
1150 : 1134 : uint32_t port_out_id = p->entries[i]->port_id;
1151 : : struct rte_port_out *port_out =
1152 : : &p->ports_out[port_out_id];
1153 : :
1154 : : /* Output port user actions */
1155 [ + - ]: 1134 : if (port_out->f_action == NULL) /* Output port TX */
1156 : 1134 : port_out->ops.f_tx(port_out->h_port, pkt);
1157 : : else {
1158 : 0 : uint64_t pkt_mask = 1LLU << i;
1159 : :
1160 : 0 : port_out->f_action(p,
1161 : 0 : p->pkts,
1162 : : pkt_mask,
1163 : : port_out->arg_ah);
1164 : :
1165 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1166 : : port_out->n_pkts_dropped_by_ah);
1167 : :
1168 : : /* Output port TX */
1169 [ # # ]: 0 : if (pkt_mask & p->pkts_mask)
1170 : 0 : port_out->ops.f_tx(port_out->h_port,
1171 : : pkt);
1172 : : }
1173 : : }
1174 : : } else {
1175 : : uint32_t i;
1176 : :
1177 [ + + ]: 130 : for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1178 : 128 : uint64_t pkt_mask = 1LLU << i;
1179 : : struct rte_mbuf *pkt;
1180 : : struct rte_port_out *port_out;
1181 : : uint32_t port_out_id;
1182 : :
1183 [ + + ]: 128 : if ((pkt_mask & pkts_mask) == 0)
1184 : 118 : continue;
1185 : :
1186 : 10 : pkt = p->pkts[i];
1187 : 10 : port_out_id = p->entries[i]->port_id;
1188 : : port_out = &p->ports_out[port_out_id];
1189 : :
1190 : : /* Output port user actions */
1191 [ + - ]: 10 : if (port_out->f_action == NULL) /* Output port TX */
1192 : 10 : port_out->ops.f_tx(port_out->h_port, pkt);
1193 : : else {
1194 : 0 : port_out->f_action(p,
1195 : 0 : p->pkts,
1196 : : pkt_mask,
1197 : : port_out->arg_ah);
1198 : :
1199 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1200 : : port_out->n_pkts_dropped_by_ah);
1201 : :
1202 : : /* Output port TX */
1203 [ # # ]: 0 : if (pkt_mask & p->pkts_mask)
1204 : 0 : port_out->ops.f_tx(port_out->h_port,
1205 : : pkt);
1206 : : }
1207 : : }
1208 : : }
1209 : 70 : }
1210 : :
1211 : : static inline void
1212 : 70 : rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1213 : : uint64_t pkts_mask)
1214 : : {
1215 : 70 : p->pkts_mask = pkts_mask;
1216 : :
1217 [ + - ]: 70 : if ((pkts_mask & (pkts_mask + 1)) == 0) {
1218 : : uint64_t n_pkts = rte_popcount64(pkts_mask);
1219 : : uint32_t i;
1220 : :
1221 [ - + ]: 70 : for (i = 0; i < n_pkts; i++) {
1222 : 0 : struct rte_mbuf *pkt = p->pkts[i];
1223 : 0 : uint32_t port_out_id =
1224 : 0 : RTE_MBUF_METADATA_UINT32(pkt,
1225 : : p->offset_port_id);
1226 : : struct rte_port_out *port_out = &p->ports_out[
1227 : : port_out_id];
1228 : :
1229 : : /* Output port user actions */
1230 [ # # ]: 0 : if (port_out->f_action == NULL) /* Output port TX */
1231 : 0 : port_out->ops.f_tx(port_out->h_port, pkt);
1232 : : else {
1233 : 0 : uint64_t pkt_mask = 1LLU << i;
1234 : :
1235 : 0 : port_out->f_action(p,
1236 : 0 : p->pkts,
1237 : : pkt_mask,
1238 : : port_out->arg_ah);
1239 : :
1240 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1241 : : port_out->n_pkts_dropped_by_ah);
1242 : :
1243 : : /* Output port TX */
1244 [ # # ]: 0 : if (pkt_mask & p->pkts_mask)
1245 : 0 : port_out->ops.f_tx(port_out->h_port,
1246 : : pkt);
1247 : : }
1248 : : }
1249 : : } else {
1250 : : uint32_t i;
1251 : :
1252 [ # # ]: 0 : for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1253 : 0 : uint64_t pkt_mask = 1LLU << i;
1254 : : struct rte_mbuf *pkt;
1255 : : struct rte_port_out *port_out;
1256 : : uint32_t port_out_id;
1257 : :
1258 [ # # ]: 0 : if ((pkt_mask & pkts_mask) == 0)
1259 : 0 : continue;
1260 : :
1261 : 0 : pkt = p->pkts[i];
1262 : 0 : port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1263 : : p->offset_port_id);
1264 : : port_out = &p->ports_out[port_out_id];
1265 : :
1266 : : /* Output port user actions */
1267 [ # # ]: 0 : if (port_out->f_action == NULL) /* Output port TX */
1268 : 0 : port_out->ops.f_tx(port_out->h_port, pkt);
1269 : : else {
1270 : 0 : port_out->f_action(p,
1271 : 0 : p->pkts,
1272 : : pkt_mask,
1273 : : port_out->arg_ah);
1274 : :
1275 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1276 : : port_out->n_pkts_dropped_by_ah);
1277 : :
1278 : : /* Output port TX */
1279 [ # # ]: 0 : if (pkt_mask & p->pkts_mask)
1280 : 0 : port_out->ops.f_tx(port_out->h_port,
1281 : : pkt);
1282 : : }
1283 : : }
1284 : : }
1285 : 70 : }
1286 : :
1287 : : static inline void
1288 : 70 : rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1289 : : {
1290 [ + + ]: 70 : if ((pkts_mask & (pkts_mask + 1)) == 0) {
1291 : : uint64_t n_pkts = rte_popcount64(pkts_mask);
1292 : : uint32_t i;
1293 : :
1294 [ + + ]: 520 : for (i = 0; i < n_pkts; i++)
1295 : 465 : rte_pktmbuf_free(p->pkts[i]);
1296 : : } else {
1297 : : uint32_t i;
1298 : :
1299 [ + + ]: 975 : for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1300 : 960 : uint64_t pkt_mask = 1LLU << i;
1301 : :
1302 [ + + ]: 960 : if ((pkt_mask & pkts_mask) == 0)
1303 : 725 : continue;
1304 : :
1305 : 235 : rte_pktmbuf_free(p->pkts[i]);
1306 : : }
1307 : : }
1308 : 70 : }
1309 : :
1310 : : int
1311 : 84 : rte_pipeline_run(struct rte_pipeline *p)
1312 : : {
1313 : 84 : struct rte_port_in *port_in = p->port_in_next;
1314 : : uint32_t n_pkts, table_id;
1315 : :
1316 [ + - ]: 84 : if (port_in == NULL)
1317 : : return 0;
1318 : :
1319 : : /* Input port RX */
1320 : 84 : n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1321 : : port_in->burst_size);
1322 [ + + ]: 84 : if (n_pkts == 0) {
1323 : 14 : p->port_in_next = port_in->next;
1324 : 14 : return 0;
1325 : : }
1326 : :
1327 : 70 : p->pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1328 : 70 : p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1329 : 70 : p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1330 : 70 : p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1331 : 70 : p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1332 : :
1333 : : /* Input port user actions */
1334 [ - + ]: 70 : if (port_in->f_action != NULL) {
1335 : 0 : port_in->f_action(p, p->pkts, n_pkts, port_in->arg_ah);
1336 : :
1337 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1338 : : port_in->n_pkts_dropped_by_ah);
1339 : : }
1340 : :
1341 : : /* Table */
1342 [ + + ]: 144 : for (table_id = port_in->table_id; p->pkts_mask != 0; ) {
1343 : : struct rte_table *table;
1344 : : uint64_t lookup_hit_mask, lookup_miss_mask;
1345 : :
1346 : : /* Lookup */
1347 : : table = &p->tables[table_id];
1348 : 74 : table->ops.f_lookup(table->h_table, p->pkts, p->pkts_mask,
1349 : 74 : &lookup_hit_mask, (void **) p->entries);
1350 : 74 : lookup_miss_mask = p->pkts_mask & (~lookup_hit_mask);
1351 : :
1352 : : /* Lookup miss */
1353 [ + + ]: 74 : if (lookup_miss_mask != 0) {
1354 : 47 : struct rte_pipeline_table_entry *default_entry =
1355 : : table->default_entry;
1356 : :
1357 : 47 : p->pkts_mask = lookup_miss_mask;
1358 : :
1359 : : /* Table user actions */
1360 [ + + ]: 47 : if (table->f_action_miss != NULL) {
1361 : 10 : table->f_action_miss(p,
1362 : : p->pkts,
1363 : : lookup_miss_mask,
1364 : : default_entry,
1365 : : table->arg_ah);
1366 : :
1367 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1368 : : table->n_pkts_dropped_by_lkp_miss_ah);
1369 : : }
1370 : :
1371 : : /* Table reserved actions */
1372 [ + + ]: 47 : if ((default_entry->action == RTE_PIPELINE_ACTION_PORT) &&
1373 [ + - ]: 12 : (p->pkts_mask != 0))
1374 : 12 : rte_pipeline_action_handler_port_bulk(p,
1375 : : p->pkts_mask,
1376 : : default_entry->port_id);
1377 : : else {
1378 : : uint32_t pos = default_entry->action;
1379 : :
1380 : : RTE_PIPELINE_STATS_TABLE_DROP0(p);
1381 : :
1382 : 35 : p->action_mask0[pos] |= p->pkts_mask;
1383 : :
1384 : : RTE_PIPELINE_STATS_TABLE_DROP1(p,
1385 : : table->n_pkts_dropped_lkp_miss);
1386 : : }
1387 : : }
1388 : :
1389 : : /* Lookup hit */
1390 [ + + ]: 74 : if (lookup_hit_mask != 0) {
1391 : 38 : p->pkts_mask = lookup_hit_mask;
1392 : :
1393 : : /* Table user actions */
1394 [ - + ]: 38 : if (table->f_action_hit != NULL) {
1395 : 0 : table->f_action_hit(p,
1396 : : p->pkts,
1397 : : lookup_hit_mask,
1398 : : p->entries,
1399 : : table->arg_ah);
1400 : :
1401 : : RTE_PIPELINE_STATS_AH_DROP_READ(p,
1402 : : table->n_pkts_dropped_by_lkp_hit_ah);
1403 : : }
1404 : :
1405 : : /* Table reserved actions */
1406 : : RTE_PIPELINE_STATS_TABLE_DROP0(p);
1407 : 38 : rte_pipeline_compute_masks(p, p->pkts_mask);
1408 : 38 : p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1409 : 38 : p->action_mask1[
1410 : : RTE_PIPELINE_ACTION_DROP];
1411 : 38 : p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1412 : 38 : p->action_mask1[
1413 : : RTE_PIPELINE_ACTION_PORT];
1414 : 38 : p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1415 : 38 : p->action_mask1[
1416 : : RTE_PIPELINE_ACTION_PORT_META];
1417 : 38 : p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1418 : 38 : p->action_mask1[
1419 : : RTE_PIPELINE_ACTION_TABLE];
1420 : :
1421 : : RTE_PIPELINE_STATS_TABLE_DROP1(p,
1422 : : table->n_pkts_dropped_lkp_hit);
1423 : : }
1424 : :
1425 : : /* Prepare for next iteration */
1426 : 74 : p->pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1427 : 74 : table_id = table->table_next_id;
1428 : 74 : p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1429 : : }
1430 : :
1431 : : /* Table reserved action PORT */
1432 : 70 : rte_pipeline_action_handler_port(p,
1433 : : p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1434 : :
1435 : : /* Table reserved action PORT META */
1436 : 70 : rte_pipeline_action_handler_port_meta(p,
1437 : : p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1438 : :
1439 : : /* Table reserved action DROP */
1440 : 70 : rte_pipeline_action_handler_drop(p,
1441 : : p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1442 : :
1443 : : /* Pick candidate for next port IN to serve */
1444 : 70 : p->port_in_next = port_in->next;
1445 : :
1446 : 70 : return (int) n_pkts;
1447 : : }
1448 : :
1449 : : int
1450 : 69 : rte_pipeline_flush(struct rte_pipeline *p)
1451 : : {
1452 : : uint32_t port_id;
1453 : :
1454 : : /* Check input arguments */
1455 [ + + ]: 69 : if (p == NULL) {
1456 : 7 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
1457 : : __func__);
1458 : 7 : return -EINVAL;
1459 : : }
1460 : :
1461 [ + + ]: 186 : for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1462 : : struct rte_port_out *port = &p->ports_out[port_id];
1463 : :
1464 [ + - ]: 124 : if (port->ops.f_flush != NULL)
1465 : 124 : port->ops.f_flush(port->h_port);
1466 : : }
1467 : :
1468 : : return 0;
1469 : : }
1470 : :
1471 : : int
1472 : 0 : rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1473 : : uint32_t port_id, struct rte_mbuf *pkt)
1474 : : {
1475 : : struct rte_port_out *port_out = &p->ports_out[port_id];
1476 : :
1477 : 0 : port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1478 : :
1479 : 0 : return 0;
1480 : : }
1481 : :
1482 : 0 : int rte_pipeline_ah_packet_hijack(struct rte_pipeline *p,
1483 : : uint64_t pkts_mask)
1484 : : {
1485 : 0 : pkts_mask &= p->pkts_mask;
1486 : 0 : p->pkts_mask &= ~pkts_mask;
1487 : :
1488 : 0 : return 0;
1489 : : }
1490 : :
1491 : 10 : int rte_pipeline_ah_packet_drop(struct rte_pipeline *p,
1492 : : uint64_t pkts_mask)
1493 : : {
1494 : 10 : pkts_mask &= p->pkts_mask;
1495 : 10 : p->pkts_mask &= ~pkts_mask;
1496 : 10 : p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask;
1497 : :
1498 : : RTE_PIPELINE_STATS_AH_DROP_WRITE(p, pkts_mask);
1499 : 10 : return 0;
1500 : : }
1501 : :
1502 : 0 : int rte_pipeline_port_in_stats_read(struct rte_pipeline *p, uint32_t port_id,
1503 : : struct rte_pipeline_port_in_stats *stats, int clear)
1504 : : {
1505 : : struct rte_port_in *port;
1506 : : int retval;
1507 : :
1508 [ # # ]: 0 : if (p == NULL) {
1509 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
1510 : : __func__);
1511 : 0 : return -EINVAL;
1512 : : }
1513 : :
1514 [ # # ]: 0 : if (port_id >= p->num_ports_in) {
1515 : 0 : PIPELINE_LOG(ERR,
1516 : : "%s: port IN ID %u is out of range",
1517 : : __func__, port_id);
1518 : 0 : return -EINVAL;
1519 : : }
1520 : :
1521 : : port = &p->ports_in[port_id];
1522 : :
1523 [ # # ]: 0 : if (port->ops.f_stats != NULL) {
1524 : 0 : retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1525 [ # # ]: 0 : if (retval)
1526 : : return retval;
1527 [ # # ]: 0 : } else if (stats != NULL)
1528 : 0 : memset(&stats->stats, 0, sizeof(stats->stats));
1529 : :
1530 [ # # ]: 0 : if (stats != NULL)
1531 : 0 : stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1532 : :
1533 [ # # ]: 0 : if (clear != 0)
1534 : 0 : port->n_pkts_dropped_by_ah = 0;
1535 : :
1536 : : return 0;
1537 : : }
1538 : :
1539 : 0 : int rte_pipeline_port_out_stats_read(struct rte_pipeline *p, uint32_t port_id,
1540 : : struct rte_pipeline_port_out_stats *stats, int clear)
1541 : : {
1542 : : struct rte_port_out *port;
1543 : : int retval;
1544 : :
1545 [ # # ]: 0 : if (p == NULL) {
1546 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL", __func__);
1547 : 0 : return -EINVAL;
1548 : : }
1549 : :
1550 [ # # ]: 0 : if (port_id >= p->num_ports_out) {
1551 : 0 : PIPELINE_LOG(ERR,
1552 : : "%s: port OUT ID %u is out of range", __func__, port_id);
1553 : 0 : return -EINVAL;
1554 : : }
1555 : :
1556 : : port = &p->ports_out[port_id];
1557 [ # # ]: 0 : if (port->ops.f_stats != NULL) {
1558 : 0 : retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1559 [ # # ]: 0 : if (retval != 0)
1560 : : return retval;
1561 [ # # ]: 0 : } else if (stats != NULL)
1562 : 0 : memset(&stats->stats, 0, sizeof(stats->stats));
1563 : :
1564 [ # # ]: 0 : if (stats != NULL)
1565 : 0 : stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1566 : :
1567 [ # # ]: 0 : if (clear != 0)
1568 : 0 : port->n_pkts_dropped_by_ah = 0;
1569 : :
1570 : : return 0;
1571 : : }
1572 : :
1573 : 0 : int rte_pipeline_table_stats_read(struct rte_pipeline *p, uint32_t table_id,
1574 : : struct rte_pipeline_table_stats *stats, int clear)
1575 : : {
1576 : : struct rte_table *table;
1577 : : int retval;
1578 : :
1579 [ # # ]: 0 : if (p == NULL) {
1580 : 0 : PIPELINE_LOG(ERR, "%s: pipeline parameter NULL",
1581 : : __func__);
1582 : 0 : return -EINVAL;
1583 : : }
1584 : :
1585 [ # # ]: 0 : if (table_id >= p->num_tables) {
1586 : 0 : PIPELINE_LOG(ERR,
1587 : : "%s: table %u is out of range", __func__, table_id);
1588 : 0 : return -EINVAL;
1589 : : }
1590 : :
1591 : : table = &p->tables[table_id];
1592 [ # # ]: 0 : if (table->ops.f_stats != NULL) {
1593 : 0 : retval = table->ops.f_stats(table->h_table, &stats->stats, clear);
1594 [ # # ]: 0 : if (retval != 0)
1595 : : return retval;
1596 [ # # ]: 0 : } else if (stats != NULL)
1597 : 0 : memset(&stats->stats, 0, sizeof(stats->stats));
1598 : :
1599 [ # # ]: 0 : if (stats != NULL) {
1600 : 0 : stats->n_pkts_dropped_by_lkp_hit_ah =
1601 : 0 : table->n_pkts_dropped_by_lkp_hit_ah;
1602 : 0 : stats->n_pkts_dropped_by_lkp_miss_ah =
1603 : 0 : table->n_pkts_dropped_by_lkp_miss_ah;
1604 : 0 : stats->n_pkts_dropped_lkp_hit = table->n_pkts_dropped_lkp_hit;
1605 : 0 : stats->n_pkts_dropped_lkp_miss = table->n_pkts_dropped_lkp_miss;
1606 : : }
1607 : :
1608 [ # # ]: 0 : if (clear != 0) {
1609 : 0 : table->n_pkts_dropped_by_lkp_hit_ah = 0;
1610 : 0 : table->n_pkts_dropped_by_lkp_miss_ah = 0;
1611 : 0 : table->n_pkts_dropped_lkp_hit = 0;
1612 : 0 : table->n_pkts_dropped_lkp_miss = 0;
1613 : : }
1614 : :
1615 : : return 0;
1616 : : }
|