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