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