xref: /dpdk/drivers/net/softnic/rte_eth_softnic_thread.c (revision b9bcbeeccbf56c8deff19a32b07e4bc1b8fa0411)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 
7 #include <rte_common.h>
8 #include <rte_cycles.h>
9 #include <rte_lcore.h>
10 #include <rte_ring.h>
11 
12 #include <rte_table_acl.h>
13 #include <rte_table_array.h>
14 #include <rte_table_hash.h>
15 #include <rte_table_lpm.h>
16 #include <rte_table_lpm_ipv6.h>
17 #include "rte_eth_softnic_internals.h"
18 
19 /**
20  * Master thread: data plane thread init
21  */
22 void
23 softnic_thread_free(struct pmd_internals *softnic)
24 {
25 	uint32_t i;
26 
27 	RTE_LCORE_FOREACH_SLAVE(i) {
28 		struct softnic_thread *t = &softnic->thread[i];
29 
30 		/* MSGQs */
31 		if (t->msgq_req)
32 			rte_ring_free(t->msgq_req);
33 
34 		if (t->msgq_rsp)
35 			rte_ring_free(t->msgq_rsp);
36 	}
37 }
38 
39 int
40 softnic_thread_init(struct pmd_internals *softnic)
41 {
42 	uint32_t i;
43 
44 	RTE_LCORE_FOREACH_SLAVE(i) {
45 		char ring_name[NAME_MAX];
46 		struct rte_ring *msgq_req, *msgq_rsp;
47 		struct softnic_thread *t = &softnic->thread[i];
48 		struct softnic_thread_data *t_data = &softnic->thread_data[i];
49 		uint32_t cpu_id = rte_lcore_to_socket_id(i);
50 
51 		/* MSGQs */
52 		snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
53 			softnic->params.name,
54 			i);
55 
56 		msgq_req = rte_ring_create(ring_name,
57 			THREAD_MSGQ_SIZE,
58 			cpu_id,
59 			RING_F_SP_ENQ | RING_F_SC_DEQ);
60 
61 		if (msgq_req == NULL) {
62 			softnic_thread_free(softnic);
63 			return -1;
64 		}
65 
66 		snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
67 			softnic->params.name,
68 			i);
69 
70 		msgq_rsp = rte_ring_create(ring_name,
71 			THREAD_MSGQ_SIZE,
72 			cpu_id,
73 			RING_F_SP_ENQ | RING_F_SC_DEQ);
74 
75 		if (msgq_rsp == NULL) {
76 			softnic_thread_free(softnic);
77 			return -1;
78 		}
79 
80 		/* Master thread records */
81 		t->msgq_req = msgq_req;
82 		t->msgq_rsp = msgq_rsp;
83 		t->enabled = 1;
84 
85 		/* Data plane thread records */
86 		t_data->n_pipelines = 0;
87 		t_data->msgq_req = msgq_req;
88 		t_data->msgq_rsp = msgq_rsp;
89 		t_data->timer_period =
90 			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
91 		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
92 		t_data->time_next_min = t_data->time_next;
93 	}
94 
95 	return 0;
96 }
97 
98 static inline int
99 thread_is_running(uint32_t thread_id)
100 {
101 	enum rte_lcore_state_t thread_state;
102 
103 	thread_state = rte_eal_get_lcore_state(thread_id);
104 	return (thread_state == RUNNING)? 1 : 0;
105 }
106 
107 /**
108  * Pipeline is running when:
109  *    (A) Pipeline is mapped to a data plane thread AND
110  *    (B) Its data plane thread is in RUNNING state.
111  */
112 static inline int
113 pipeline_is_running(struct pipeline *p)
114 {
115 	if (p->enabled == 0)
116 		return 0;
117 
118 	return thread_is_running(p->thread_id);
119 }
120 
121 /**
122  * Master thread & data plane threads: message passing
123  */
124 enum thread_req_type {
125 	THREAD_REQ_PIPELINE_ENABLE = 0,
126 	THREAD_REQ_PIPELINE_DISABLE,
127 	THREAD_REQ_MAX
128 };
129 
130 struct thread_msg_req {
131 	enum thread_req_type type;
132 
133 	union {
134 		struct {
135 			struct rte_pipeline *p;
136 			struct {
137 				struct rte_table_action *a;
138 			} table[RTE_PIPELINE_TABLE_MAX];
139 			struct rte_ring *msgq_req;
140 			struct rte_ring *msgq_rsp;
141 			uint32_t timer_period_ms;
142 			uint32_t n_tables;
143 		} pipeline_enable;
144 
145 		struct {
146 			struct rte_pipeline *p;
147 		} pipeline_disable;
148 	};
149 };
150 
151 struct thread_msg_rsp {
152 	int status;
153 };
154 
155 /**
156  * Master thread
157  */
158 static struct thread_msg_req *
159 thread_msg_alloc(void)
160 {
161 	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
162 		sizeof(struct thread_msg_rsp));
163 
164 	return calloc(1, size);
165 }
166 
167 static void
168 thread_msg_free(struct thread_msg_rsp *rsp)
169 {
170 	free(rsp);
171 }
172 
173 static struct thread_msg_rsp *
174 thread_msg_send_recv(struct pmd_internals *softnic,
175 	uint32_t thread_id,
176 	struct thread_msg_req *req)
177 {
178 	struct softnic_thread *t = &softnic->thread[thread_id];
179 	struct rte_ring *msgq_req = t->msgq_req;
180 	struct rte_ring *msgq_rsp = t->msgq_rsp;
181 	struct thread_msg_rsp *rsp;
182 	int status;
183 
184 	/* send */
185 	do {
186 		status = rte_ring_sp_enqueue(msgq_req, req);
187 	} while (status == -ENOBUFS);
188 
189 	/* recv */
190 	do {
191 		status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
192 	} while (status != 0);
193 
194 	return rsp;
195 }
196 
197 int
198 softnic_thread_pipeline_enable(struct pmd_internals *softnic,
199 	uint32_t thread_id,
200 	const char *pipeline_name)
201 {
202 	struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
203 	struct softnic_thread *t;
204 	struct thread_msg_req *req;
205 	struct thread_msg_rsp *rsp;
206 	uint32_t i;
207 	int status;
208 
209 	/* Check input params */
210 	if ((thread_id >= RTE_MAX_LCORE) ||
211 		(p == NULL) ||
212 		(p->n_ports_in == 0) ||
213 		(p->n_ports_out == 0) ||
214 		(p->n_tables == 0))
215 		return -1;
216 
217 	t = &softnic->thread[thread_id];
218 	if ((t->enabled == 0) ||
219 		p->enabled)
220 		return -1;
221 
222 	if (!thread_is_running(thread_id)) {
223 		struct softnic_thread_data *td = &softnic->thread_data[thread_id];
224 		struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
225 
226 		if (td->n_pipelines >= THREAD_PIPELINES_MAX)
227 			return -1;
228 
229 		/* Data plane thread */
230 		td->p[td->n_pipelines] = p->p;
231 
232 		tdp->p = p->p;
233 		for (i = 0; i < p->n_tables; i++)
234 			tdp->table_data[i].a =
235 				p->table[i].a;
236 		tdp->n_tables = p->n_tables;
237 
238 		tdp->msgq_req = p->msgq_req;
239 		tdp->msgq_rsp = p->msgq_rsp;
240 		tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
241 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
242 
243 		td->n_pipelines++;
244 
245 		/* Pipeline */
246 		p->thread_id = thread_id;
247 		p->enabled = 1;
248 
249 		return 0;
250 	}
251 
252 	/* Allocate request */
253 	req = thread_msg_alloc();
254 	if (req == NULL)
255 		return -1;
256 
257 	/* Write request */
258 	req->type = THREAD_REQ_PIPELINE_ENABLE;
259 	req->pipeline_enable.p = p->p;
260 	for (i = 0; i < p->n_tables; i++)
261 		req->pipeline_enable.table[i].a =
262 			p->table[i].a;
263 	req->pipeline_enable.msgq_req = p->msgq_req;
264 	req->pipeline_enable.msgq_rsp = p->msgq_rsp;
265 	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
266 	req->pipeline_enable.n_tables = p->n_tables;
267 
268 	/* Send request and wait for response */
269 	rsp = thread_msg_send_recv(softnic, thread_id, req);
270 	if (rsp == NULL)
271 		return -1;
272 
273 	/* Read response */
274 	status = rsp->status;
275 
276 	/* Free response */
277 	thread_msg_free(rsp);
278 
279 	/* Request completion */
280 	if (status)
281 		return status;
282 
283 	p->thread_id = thread_id;
284 	p->enabled = 1;
285 
286 	return 0;
287 }
288 
289 int
290 softnic_thread_pipeline_disable(struct pmd_internals *softnic,
291 	uint32_t thread_id,
292 	const char *pipeline_name)
293 {
294 	struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
295 	struct softnic_thread *t;
296 	struct thread_msg_req *req;
297 	struct thread_msg_rsp *rsp;
298 	int status;
299 
300 	/* Check input params */
301 	if ((thread_id >= RTE_MAX_LCORE) ||
302 		(p == NULL))
303 		return -1;
304 
305 	t = &softnic->thread[thread_id];
306 	if (t->enabled == 0)
307 		return -1;
308 
309 	if (p->enabled == 0)
310 		return 0;
311 
312 	if (p->thread_id != thread_id)
313 		return -1;
314 
315 	if (!thread_is_running(thread_id)) {
316 		struct softnic_thread_data *td = &softnic->thread_data[thread_id];
317 		uint32_t i;
318 
319 		for (i = 0; i < td->n_pipelines; i++) {
320 			struct pipeline_data *tdp = &td->pipeline_data[i];
321 
322 			if (tdp->p != p->p)
323 				continue;
324 
325 			/* Data plane thread */
326 			if (i < td->n_pipelines - 1) {
327 				struct rte_pipeline *pipeline_last =
328 					td->p[td->n_pipelines - 1];
329 				struct pipeline_data *tdp_last =
330 					&td->pipeline_data[td->n_pipelines - 1];
331 
332 				td->p[i] = pipeline_last;
333 				memcpy(tdp, tdp_last, sizeof(*tdp));
334 			}
335 
336 			td->n_pipelines--;
337 
338 			/* Pipeline */
339 			p->enabled = 0;
340 
341 			break;
342 		}
343 
344 		return 0;
345 	}
346 
347 	/* Allocate request */
348 	req = thread_msg_alloc();
349 	if (req == NULL)
350 		return -1;
351 
352 	/* Write request */
353 	req->type = THREAD_REQ_PIPELINE_DISABLE;
354 	req->pipeline_disable.p = p->p;
355 
356 	/* Send request and wait for response */
357 	rsp = thread_msg_send_recv(softnic, thread_id, req);
358 	if (rsp == NULL)
359 		return -1;
360 
361 	/* Read response */
362 	status = rsp->status;
363 
364 	/* Free response */
365 	thread_msg_free(rsp);
366 
367 	/* Request completion */
368 	if (status)
369 		return status;
370 
371 	p->enabled = 0;
372 
373 	return 0;
374 }
375 
376 /**
377  * Data plane threads: message handling
378  */
379 static inline struct thread_msg_req *
380 thread_msg_recv(struct rte_ring *msgq_req)
381 {
382 	struct thread_msg_req *req;
383 
384 	int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
385 
386 	if (status != 0)
387 		return NULL;
388 
389 	return req;
390 }
391 
392 static inline void
393 thread_msg_send(struct rte_ring *msgq_rsp,
394 	struct thread_msg_rsp *rsp)
395 {
396 	int status;
397 
398 	do {
399 		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
400 	} while (status == -ENOBUFS);
401 }
402 
403 static struct thread_msg_rsp *
404 thread_msg_handle_pipeline_enable(struct softnic_thread_data *t,
405 	struct thread_msg_req *req)
406 {
407 	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
408 	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
409 	uint32_t i;
410 
411 	/* Request */
412 	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
413 		rsp->status = -1;
414 		return rsp;
415 	}
416 
417 	t->p[t->n_pipelines] = req->pipeline_enable.p;
418 
419 	p->p = req->pipeline_enable.p;
420 	for (i = 0; i < req->pipeline_enable.n_tables; i++)
421 		p->table_data[i].a =
422 			req->pipeline_enable.table[i].a;
423 
424 	p->n_tables = req->pipeline_enable.n_tables;
425 
426 	p->msgq_req = req->pipeline_enable.msgq_req;
427 	p->msgq_rsp = req->pipeline_enable.msgq_rsp;
428 	p->timer_period =
429 		(rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
430 	p->time_next = rte_get_tsc_cycles() + p->timer_period;
431 
432 	t->n_pipelines++;
433 
434 	/* Response */
435 	rsp->status = 0;
436 	return rsp;
437 }
438 
439 static struct thread_msg_rsp *
440 thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
441 	struct thread_msg_req *req)
442 {
443 	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
444 	uint32_t n_pipelines = t->n_pipelines;
445 	struct rte_pipeline *pipeline = req->pipeline_disable.p;
446 	uint32_t i;
447 
448 	/* find pipeline */
449 	for (i = 0; i < n_pipelines; i++) {
450 		struct pipeline_data *p = &t->pipeline_data[i];
451 
452 		if (p->p != pipeline)
453 			continue;
454 
455 		if (i < n_pipelines - 1) {
456 			struct rte_pipeline *pipeline_last =
457 				t->p[n_pipelines - 1];
458 			struct pipeline_data *p_last =
459 				&t->pipeline_data[n_pipelines - 1];
460 
461 			t->p[i] = pipeline_last;
462 			memcpy(p, p_last, sizeof(*p));
463 		}
464 
465 		t->n_pipelines--;
466 
467 		rsp->status = 0;
468 		return rsp;
469 	}
470 
471 	/* should not get here */
472 	rsp->status = 0;
473 	return rsp;
474 }
475 
476 static void
477 thread_msg_handle(struct softnic_thread_data *t)
478 {
479 	for ( ; ; ) {
480 		struct thread_msg_req *req;
481 		struct thread_msg_rsp *rsp;
482 
483 		req = thread_msg_recv(t->msgq_req);
484 		if (req == NULL)
485 			break;
486 
487 		switch (req->type) {
488 		case THREAD_REQ_PIPELINE_ENABLE:
489 			rsp = thread_msg_handle_pipeline_enable(t, req);
490 			break;
491 
492 		case THREAD_REQ_PIPELINE_DISABLE:
493 			rsp = thread_msg_handle_pipeline_disable(t, req);
494 			break;
495 
496 		default:
497 			rsp = (struct thread_msg_rsp *)req;
498 			rsp->status = -1;
499 		}
500 
501 		thread_msg_send(t->msgq_rsp, rsp);
502 	}
503 }
504 
505 /**
506  * Master thread & data plane threads: message passing
507  */
508 enum pipeline_req_type {
509 	/* Port IN */
510 	PIPELINE_REQ_PORT_IN_STATS_READ,
511 	PIPELINE_REQ_PORT_IN_ENABLE,
512 	PIPELINE_REQ_PORT_IN_DISABLE,
513 
514 	/* Port OUT */
515 	PIPELINE_REQ_PORT_OUT_STATS_READ,
516 
517 	/* Table */
518 	PIPELINE_REQ_TABLE_STATS_READ,
519 	PIPELINE_REQ_TABLE_RULE_ADD,
520 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
521 	PIPELINE_REQ_TABLE_RULE_ADD_BULK,
522 	PIPELINE_REQ_TABLE_RULE_DELETE,
523 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
524 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
525 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
526 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
527 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
528 	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
529 	PIPELINE_REQ_TABLE_RULE_TTL_READ,
530 	PIPELINE_REQ_MAX
531 };
532 
533 struct pipeline_msg_req_port_in_stats_read {
534 	int clear;
535 };
536 
537 struct pipeline_msg_req_port_out_stats_read {
538 	int clear;
539 };
540 
541 struct pipeline_msg_req_table_stats_read {
542 	int clear;
543 };
544 
545 struct pipeline_msg_req_table_rule_add {
546 	struct softnic_table_rule_match match;
547 	struct softnic_table_rule_action action;
548 };
549 
550 struct pipeline_msg_req_table_rule_add_default {
551 	struct softnic_table_rule_action action;
552 };
553 
554 struct pipeline_msg_req_table_rule_add_bulk {
555 	struct softnic_table_rule_match *match;
556 	struct softnic_table_rule_action *action;
557 	void **data;
558 	uint32_t n_rules;
559 	int bulk;
560 };
561 
562 struct pipeline_msg_req_table_rule_delete {
563 	struct softnic_table_rule_match match;
564 };
565 
566 struct pipeline_msg_req_table_rule_stats_read {
567 	void *data;
568 	int clear;
569 };
570 
571 struct pipeline_msg_req_table_mtr_profile_add {
572 	uint32_t meter_profile_id;
573 	struct rte_table_action_meter_profile profile;
574 };
575 
576 struct pipeline_msg_req_table_mtr_profile_delete {
577 	uint32_t meter_profile_id;
578 };
579 
580 struct pipeline_msg_req_table_rule_mtr_read {
581 	void *data;
582 	uint32_t tc_mask;
583 	int clear;
584 };
585 
586 struct pipeline_msg_req_table_dscp_table_update {
587 	uint64_t dscp_mask;
588 	struct rte_table_action_dscp_table dscp_table;
589 };
590 
591 struct pipeline_msg_req_table_rule_ttl_read {
592 	void *data;
593 	int clear;
594 };
595 
596 struct pipeline_msg_req {
597 	enum pipeline_req_type type;
598 	uint32_t id; /* Port IN, port OUT or table ID */
599 
600 	RTE_STD_C11
601 	union {
602 		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
603 		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
604 		struct pipeline_msg_req_table_stats_read table_stats_read;
605 		struct pipeline_msg_req_table_rule_add table_rule_add;
606 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
607 		struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
608 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
609 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
610 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
611 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
612 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
613 		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
614 		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
615 	};
616 };
617 
618 struct pipeline_msg_rsp_port_in_stats_read {
619 	struct rte_pipeline_port_in_stats stats;
620 };
621 
622 struct pipeline_msg_rsp_port_out_stats_read {
623 	struct rte_pipeline_port_out_stats stats;
624 };
625 
626 struct pipeline_msg_rsp_table_stats_read {
627 	struct rte_pipeline_table_stats stats;
628 };
629 
630 struct pipeline_msg_rsp_table_rule_add {
631 	void *data;
632 };
633 
634 struct pipeline_msg_rsp_table_rule_add_default {
635 	void *data;
636 };
637 
638 struct pipeline_msg_rsp_table_rule_add_bulk {
639 	uint32_t n_rules;
640 };
641 
642 struct pipeline_msg_rsp_table_rule_stats_read {
643 	struct rte_table_action_stats_counters stats;
644 };
645 
646 struct pipeline_msg_rsp_table_rule_mtr_read {
647 	struct rte_table_action_mtr_counters stats;
648 };
649 
650 struct pipeline_msg_rsp_table_rule_ttl_read {
651 	struct rte_table_action_ttl_counters stats;
652 };
653 
654 struct pipeline_msg_rsp {
655 	int status;
656 
657 	RTE_STD_C11
658 	union {
659 		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
660 		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
661 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
662 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
663 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
664 		struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
665 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
666 		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
667 		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
668 	};
669 };
670 
671 /**
672  * Master thread
673  */
674 static struct pipeline_msg_req *
675 pipeline_msg_alloc(void)
676 {
677 	size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
678 		sizeof(struct pipeline_msg_rsp));
679 
680 	return calloc(1, size);
681 }
682 
683 static void
684 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
685 {
686 	free(rsp);
687 }
688 
689 static struct pipeline_msg_rsp *
690 pipeline_msg_send_recv(struct pipeline *p,
691 	struct pipeline_msg_req *req)
692 {
693 	struct rte_ring *msgq_req = p->msgq_req;
694 	struct rte_ring *msgq_rsp = p->msgq_rsp;
695 	struct pipeline_msg_rsp *rsp;
696 	int status;
697 
698 	/* send */
699 	do {
700 		status = rte_ring_sp_enqueue(msgq_req, req);
701 	} while (status == -ENOBUFS);
702 
703 	/* recv */
704 	do {
705 		status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
706 	} while (status != 0);
707 
708 	return rsp;
709 }
710 
711 int
712 softnic_pipeline_port_in_stats_read(struct pmd_internals *softnic,
713 	const char *pipeline_name,
714 	uint32_t port_id,
715 	struct rte_pipeline_port_in_stats *stats,
716 	int clear)
717 {
718 	struct pipeline *p;
719 	struct pipeline_msg_req *req;
720 	struct pipeline_msg_rsp *rsp;
721 	int status;
722 
723 	/* Check input params */
724 	if (pipeline_name == NULL ||
725 		stats == NULL)
726 		return -1;
727 
728 	p = softnic_pipeline_find(softnic, pipeline_name);
729 	if (p == NULL ||
730 		port_id >= p->n_ports_in)
731 		return -1;
732 
733 	if (!pipeline_is_running(p)) {
734 		status = rte_pipeline_port_in_stats_read(p->p,
735 			port_id,
736 			stats,
737 			clear);
738 
739 		return status;
740 	}
741 
742 	/* Allocate request */
743 	req = pipeline_msg_alloc();
744 	if (req == NULL)
745 		return -1;
746 
747 	/* Write request */
748 	req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
749 	req->id = port_id;
750 	req->port_in_stats_read.clear = clear;
751 
752 	/* Send request and wait for response */
753 	rsp = pipeline_msg_send_recv(p, req);
754 	if (rsp == NULL)
755 		return -1;
756 
757 	/* Read response */
758 	status = rsp->status;
759 	if (status)
760 		memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
761 
762 	/* Free response */
763 	pipeline_msg_free(rsp);
764 
765 	return status;
766 }
767 
768 int
769 softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
770 	const char *pipeline_name,
771 	uint32_t port_id)
772 {
773 	struct pipeline *p;
774 	struct pipeline_msg_req *req;
775 	struct pipeline_msg_rsp *rsp;
776 	int status;
777 
778 	/* Check input params */
779 	if (pipeline_name == NULL)
780 		return -1;
781 
782 	p = softnic_pipeline_find(softnic, pipeline_name);
783 	if (p == NULL ||
784 		port_id >= p->n_ports_in)
785 		return -1;
786 
787 	if (!pipeline_is_running(p)) {
788 		status = rte_pipeline_port_in_enable(p->p, port_id);
789 		return status;
790 	}
791 
792 	/* Allocate request */
793 	req = pipeline_msg_alloc();
794 	if (req == NULL)
795 		return -1;
796 
797 	/* Write request */
798 	req->type = PIPELINE_REQ_PORT_IN_ENABLE;
799 	req->id = port_id;
800 
801 	/* Send request and wait for response */
802 	rsp = pipeline_msg_send_recv(p, req);
803 	if (rsp == NULL)
804 		return -1;
805 
806 	/* Read response */
807 	status = rsp->status;
808 
809 	/* Free response */
810 	pipeline_msg_free(rsp);
811 
812 	return status;
813 }
814 
815 int
816 softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
817 	const char *pipeline_name,
818 	uint32_t port_id)
819 {
820 	struct pipeline *p;
821 	struct pipeline_msg_req *req;
822 	struct pipeline_msg_rsp *rsp;
823 	int status;
824 
825 	/* Check input params */
826 	if (pipeline_name == NULL)
827 		return -1;
828 
829 	p = softnic_pipeline_find(softnic, pipeline_name);
830 	if (p == NULL ||
831 		port_id >= p->n_ports_in)
832 		return -1;
833 
834 	if (!pipeline_is_running(p)) {
835 		status = rte_pipeline_port_in_disable(p->p, port_id);
836 		return status;
837 	}
838 
839 	/* Allocate request */
840 	req = pipeline_msg_alloc();
841 	if (req == NULL)
842 		return -1;
843 
844 	/* Write request */
845 	req->type = PIPELINE_REQ_PORT_IN_DISABLE;
846 	req->id = port_id;
847 
848 	/* Send request and wait for response */
849 	rsp = pipeline_msg_send_recv(p, req);
850 	if (rsp == NULL)
851 		return -1;
852 
853 	/* Read response */
854 	status = rsp->status;
855 
856 	/* Free response */
857 	pipeline_msg_free(rsp);
858 
859 	return status;
860 }
861 
862 int
863 softnic_pipeline_port_out_stats_read(struct pmd_internals *softnic,
864 	const char *pipeline_name,
865 	uint32_t port_id,
866 	struct rte_pipeline_port_out_stats *stats,
867 	int clear)
868 {
869 	struct pipeline *p;
870 	struct pipeline_msg_req *req;
871 	struct pipeline_msg_rsp *rsp;
872 	int status;
873 
874 	/* Check input params */
875 	if (pipeline_name == NULL ||
876 		stats == NULL)
877 		return -1;
878 
879 	p = softnic_pipeline_find(softnic, pipeline_name);
880 	if (p == NULL ||
881 		port_id >= p->n_ports_out)
882 		return -1;
883 
884 	if (!pipeline_is_running(p)) {
885 		status = rte_pipeline_port_out_stats_read(p->p,
886 			port_id,
887 			stats,
888 			clear);
889 
890 		return status;
891 	}
892 
893 	/* Allocate request */
894 	req = pipeline_msg_alloc();
895 	if (req == NULL)
896 		return -1;
897 
898 	/* Write request */
899 	req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
900 	req->id = port_id;
901 	req->port_out_stats_read.clear = clear;
902 
903 	/* Send request and wait for response */
904 	rsp = pipeline_msg_send_recv(p, req);
905 	if (rsp == NULL)
906 		return -1;
907 
908 	/* Read response */
909 	status = rsp->status;
910 	if (status)
911 		memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
912 
913 	/* Free response */
914 	pipeline_msg_free(rsp);
915 
916 	return status;
917 }
918 
919 int
920 softnic_pipeline_table_stats_read(struct pmd_internals *softnic,
921 	const char *pipeline_name,
922 	uint32_t table_id,
923 	struct rte_pipeline_table_stats *stats,
924 	int clear)
925 {
926 	struct pipeline *p;
927 	struct pipeline_msg_req *req;
928 	struct pipeline_msg_rsp *rsp;
929 	int status;
930 
931 	/* Check input params */
932 	if (pipeline_name == NULL ||
933 		stats == NULL)
934 		return -1;
935 
936 	p = softnic_pipeline_find(softnic, pipeline_name);
937 	if (p == NULL ||
938 		table_id >= p->n_tables)
939 		return -1;
940 
941 	if (!pipeline_is_running(p)) {
942 		status = rte_pipeline_table_stats_read(p->p,
943 			table_id,
944 			stats,
945 			clear);
946 
947 		return status;
948 	}
949 
950 	/* Allocate request */
951 	req = pipeline_msg_alloc();
952 	if (req == NULL)
953 		return -1;
954 
955 	/* Write request */
956 	req->type = PIPELINE_REQ_TABLE_STATS_READ;
957 	req->id = table_id;
958 	req->table_stats_read.clear = clear;
959 
960 	/* Send request and wait for response */
961 	rsp = pipeline_msg_send_recv(p, req);
962 	if (rsp == NULL)
963 		return -1;
964 
965 	/* Read response */
966 	status = rsp->status;
967 	if (status)
968 		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
969 
970 	/* Free response */
971 	pipeline_msg_free(rsp);
972 
973 	return status;
974 }
975 
976 static int
977 match_check(struct softnic_table_rule_match *match,
978 	struct pipeline *p,
979 	uint32_t table_id)
980 {
981 	struct softnic_table *table;
982 
983 	if (match == NULL ||
984 		p == NULL ||
985 		table_id >= p->n_tables)
986 		return -1;
987 
988 	table = &p->table[table_id];
989 	if (match->match_type != table->params.match_type)
990 		return -1;
991 
992 	switch (match->match_type) {
993 	case TABLE_ACL:
994 	{
995 		struct softnic_table_acl_params *t = &table->params.match.acl;
996 		struct softnic_table_rule_match_acl *r = &match->match.acl;
997 
998 		if ((r->ip_version && (t->ip_version == 0)) ||
999 			((r->ip_version == 0) && t->ip_version))
1000 			return -1;
1001 
1002 		if (r->ip_version) {
1003 			if (r->sa_depth > 32 ||
1004 				r->da_depth > 32)
1005 				return -1;
1006 		} else {
1007 			if (r->sa_depth > 128 ||
1008 				r->da_depth > 128)
1009 				return -1;
1010 		}
1011 		return 0;
1012 	}
1013 
1014 	case TABLE_ARRAY:
1015 		return 0;
1016 
1017 	case TABLE_HASH:
1018 		return 0;
1019 
1020 	case TABLE_LPM:
1021 	{
1022 		struct softnic_table_lpm_params *t = &table->params.match.lpm;
1023 		struct softnic_table_rule_match_lpm *r = &match->match.lpm;
1024 
1025 		if ((r->ip_version && (t->key_size != 4)) ||
1026 			((r->ip_version == 0) && (t->key_size != 16)))
1027 			return -1;
1028 
1029 		if (r->ip_version) {
1030 			if (r->depth > 32)
1031 				return -1;
1032 		} else {
1033 			if (r->depth > 128)
1034 				return -1;
1035 		}
1036 		return 0;
1037 	}
1038 
1039 	case TABLE_STUB:
1040 		return -1;
1041 
1042 	default:
1043 		return -1;
1044 	}
1045 }
1046 
1047 static int
1048 action_check(struct softnic_table_rule_action *action,
1049 	struct pipeline *p,
1050 	uint32_t table_id)
1051 {
1052 	struct softnic_table_action_profile *ap;
1053 
1054 	if (action == NULL ||
1055 		p == NULL ||
1056 		table_id >= p->n_tables)
1057 		return -1;
1058 
1059 	ap = p->table[table_id].ap;
1060 	if (action->action_mask != ap->params.action_mask)
1061 		return -1;
1062 
1063 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1064 		if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1065 			action->fwd.id >= p->n_ports_out)
1066 			return -1;
1067 
1068 		if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1069 			action->fwd.id >= p->n_tables)
1070 			return -1;
1071 	}
1072 
1073 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1074 		uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
1075 		uint32_t tc_mask1 = action->mtr.tc_mask;
1076 
1077 		if (tc_mask1 != tc_mask0)
1078 			return -1;
1079 	}
1080 
1081 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1082 		uint32_t n_subports_per_port =
1083 			ap->params.tm.n_subports_per_port;
1084 		uint32_t n_pipes_per_subport =
1085 			ap->params.tm.n_pipes_per_subport;
1086 		uint32_t subport_id = action->tm.subport_id;
1087 		uint32_t pipe_id = action->tm.pipe_id;
1088 
1089 		if (subport_id >= n_subports_per_port ||
1090 			pipe_id >= n_pipes_per_subport)
1091 			return -1;
1092 	}
1093 
1094 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1095 		uint64_t encap_mask = ap->params.encap.encap_mask;
1096 		enum rte_table_action_encap_type type = action->encap.type;
1097 
1098 		if ((encap_mask & (1LLU << type)) == 0)
1099 			return -1;
1100 	}
1101 
1102 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1103 		int ip_version0 = ap->params.common.ip_version;
1104 		int ip_version1 = action->nat.ip_version;
1105 
1106 		if ((ip_version1 && (ip_version0 == 0)) ||
1107 			((ip_version1 == 0) && ip_version0))
1108 			return -1;
1109 	}
1110 
1111 	return 0;
1112 }
1113 
1114 static int
1115 action_default_check(struct softnic_table_rule_action *action,
1116 	struct pipeline *p,
1117 	uint32_t table_id)
1118 {
1119 	if (action == NULL ||
1120 		action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD) ||
1121 		p == NULL ||
1122 		table_id >= p->n_tables)
1123 		return -1;
1124 
1125 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1126 		if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1127 			action->fwd.id >= p->n_ports_out)
1128 			return -1;
1129 
1130 		if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1131 			action->fwd.id >= p->n_tables)
1132 			return -1;
1133 	}
1134 
1135 	return 0;
1136 }
1137 
1138 union table_rule_match_low_level {
1139 	struct rte_table_acl_rule_add_params acl_add;
1140 	struct rte_table_acl_rule_delete_params acl_delete;
1141 	struct rte_table_array_key array;
1142 	uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
1143 	struct rte_table_lpm_key lpm_ipv4;
1144 	struct rte_table_lpm_ipv6_key lpm_ipv6;
1145 };
1146 
1147 static int
1148 match_convert(struct softnic_table_rule_match *mh,
1149 	union table_rule_match_low_level *ml,
1150 	int add);
1151 
1152 static int
1153 action_convert(struct rte_table_action *a,
1154 	struct softnic_table_rule_action *action,
1155 	struct rte_pipeline_table_entry *data);
1156 
1157 int
1158 softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
1159 	const char *pipeline_name,
1160 	uint32_t table_id,
1161 	struct softnic_table_rule_match *match,
1162 	struct softnic_table_rule_action *action,
1163 	void **data)
1164 {
1165 	struct pipeline *p;
1166 	struct pipeline_msg_req *req;
1167 	struct pipeline_msg_rsp *rsp;
1168 	int status;
1169 
1170 	/* Check input params */
1171 	if (pipeline_name == NULL ||
1172 		match == NULL ||
1173 		action == NULL ||
1174 		data == NULL)
1175 		return -1;
1176 
1177 	p = softnic_pipeline_find(softnic, pipeline_name);
1178 	if (p == NULL ||
1179 		table_id >= p->n_tables ||
1180 		match_check(match, p, table_id) ||
1181 		action_check(action, p, table_id))
1182 		return -1;
1183 
1184 	if (!pipeline_is_running(p)) {
1185 		struct rte_table_action *a = p->table[table_id].a;
1186 		union table_rule_match_low_level match_ll;
1187 		struct rte_pipeline_table_entry *data_in, *data_out;
1188 		int key_found;
1189 		uint8_t *buffer;
1190 
1191 		buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1192 		if (buffer == NULL)
1193 			return -1;
1194 
1195 		/* Table match-action rule conversion */
1196 		data_in = (struct rte_pipeline_table_entry *)buffer;
1197 
1198 		status = match_convert(match, &match_ll, 1);
1199 		if (status) {
1200 			free(buffer);
1201 			return -1;
1202 		}
1203 
1204 		status = action_convert(a, action, data_in);
1205 		if (status) {
1206 			free(buffer);
1207 			return -1;
1208 		}
1209 
1210 		/* Add rule (match, action) to table */
1211 		status = rte_pipeline_table_entry_add(p->p,
1212 				table_id,
1213 				&match_ll,
1214 				data_in,
1215 				&key_found,
1216 				&data_out);
1217 		if (status) {
1218 			free(buffer);
1219 			return -1;
1220 		}
1221 
1222 		/* Write Response */
1223 		*data = data_out;
1224 
1225 		free(buffer);
1226 		return 0;
1227 	}
1228 
1229 	/* Allocate request */
1230 	req = pipeline_msg_alloc();
1231 	if (req == NULL)
1232 		return -1;
1233 
1234 	/* Write request */
1235 	req->type = PIPELINE_REQ_TABLE_RULE_ADD;
1236 	req->id = table_id;
1237 	memcpy(&req->table_rule_add.match, match, sizeof(*match));
1238 	memcpy(&req->table_rule_add.action, action, sizeof(*action));
1239 
1240 	/* Send request and wait for response */
1241 	rsp = pipeline_msg_send_recv(p, req);
1242 	if (rsp == NULL)
1243 		return -1;
1244 
1245 	/* Read response */
1246 	status = rsp->status;
1247 	if (status == 0)
1248 		*data = rsp->table_rule_add.data;
1249 
1250 	/* Free response */
1251 	pipeline_msg_free(rsp);
1252 
1253 	return status;
1254 }
1255 
1256 int
1257 softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
1258 	const char *pipeline_name,
1259 	uint32_t table_id,
1260 	struct softnic_table_rule_action *action,
1261 	void **data)
1262 {
1263 	struct pipeline *p;
1264 	struct pipeline_msg_req *req;
1265 	struct pipeline_msg_rsp *rsp;
1266 	int status;
1267 
1268 	/* Check input params */
1269 	if (pipeline_name == NULL ||
1270 		action == NULL ||
1271 		data == NULL)
1272 		return -1;
1273 
1274 	p = softnic_pipeline_find(softnic, pipeline_name);
1275 	if (p == NULL ||
1276 		table_id >= p->n_tables ||
1277 		action_default_check(action, p, table_id))
1278 		return -1;
1279 
1280 	if (!pipeline_is_running(p)) {
1281 		struct rte_pipeline_table_entry *data_in, *data_out;
1282 		uint8_t *buffer;
1283 
1284 		buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1285 		if (buffer == NULL)
1286 			return -1;
1287 
1288 		/* Apply actions */
1289 		data_in = (struct rte_pipeline_table_entry *)buffer;
1290 
1291 		data_in->action = action->fwd.action;
1292 		if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1293 			data_in->port_id = action->fwd.id;
1294 		if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1295 			data_in->table_id = action->fwd.id;
1296 
1297 		/* Add default rule to table */
1298 		status = rte_pipeline_table_default_entry_add(p->p,
1299 				table_id,
1300 				data_in,
1301 				&data_out);
1302 		if (status) {
1303 			free(buffer);
1304 			return -1;
1305 		}
1306 
1307 		/* Write Response */
1308 		*data = data_out;
1309 
1310 		free(buffer);
1311 		return 0;
1312 	}
1313 
1314 	/* Allocate request */
1315 	req = pipeline_msg_alloc();
1316 	if (req == NULL)
1317 		return -1;
1318 
1319 	/* Write request */
1320 	req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1321 	req->id = table_id;
1322 	memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1323 
1324 	/* Send request and wait for response */
1325 	rsp = pipeline_msg_send_recv(p, req);
1326 	if (rsp == NULL)
1327 		return -1;
1328 
1329 	/* Read response */
1330 	status = rsp->status;
1331 	if (status == 0)
1332 		*data = rsp->table_rule_add_default.data;
1333 
1334 	/* Free response */
1335 	pipeline_msg_free(rsp);
1336 
1337 	return status;
1338 }
1339 
1340 int
1341 softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
1342 	const char *pipeline_name,
1343 	uint32_t table_id,
1344 	struct softnic_table_rule_match *match,
1345 	struct softnic_table_rule_action *action,
1346 	void **data,
1347 	uint32_t *n_rules)
1348 {
1349 	struct pipeline *p;
1350 	struct pipeline_msg_req *req;
1351 	struct pipeline_msg_rsp *rsp;
1352 	uint32_t i;
1353 	int status;
1354 
1355 	/* Check input params */
1356 	if (pipeline_name == NULL ||
1357 		match == NULL ||
1358 		action == NULL ||
1359 		data == NULL ||
1360 		n_rules == NULL ||
1361 		(*n_rules == 0))
1362 		return -1;
1363 
1364 	p = softnic_pipeline_find(softnic, pipeline_name);
1365 	if (p == NULL ||
1366 		table_id >= p->n_tables)
1367 		return -1;
1368 
1369 	for (i = 0; i < *n_rules; i++)
1370 		if (match_check(match, p, table_id) ||
1371 			action_check(action, p, table_id))
1372 			return -1;
1373 
1374 	if (!pipeline_is_running(p)) {
1375 		struct rte_table_action *a = p->table[table_id].a;
1376 		union table_rule_match_low_level *match_ll;
1377 		uint8_t *action_ll;
1378 		void **match_ll_ptr;
1379 		struct rte_pipeline_table_entry **action_ll_ptr;
1380 		struct rte_pipeline_table_entry **entries_ptr =
1381 			(struct rte_pipeline_table_entry **)data;
1382 		uint32_t bulk =
1383 			(p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1384 		int *found;
1385 
1386 		/* Memory allocation */
1387 		match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
1388 		action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
1389 		match_ll_ptr = calloc(*n_rules, sizeof(void *));
1390 		action_ll_ptr =
1391 			calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
1392 		found = calloc(*n_rules, sizeof(int));
1393 
1394 		if (match_ll == NULL ||
1395 			action_ll == NULL ||
1396 			match_ll_ptr == NULL ||
1397 			action_ll_ptr == NULL ||
1398 			found == NULL)
1399 			goto fail;
1400 
1401 		for (i = 0; i < *n_rules; i++) {
1402 			match_ll_ptr[i] = (void *)&match_ll[i];
1403 			action_ll_ptr[i] =
1404 				(struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1405 		}
1406 
1407 		/* Rule match conversion */
1408 		for (i = 0; i < *n_rules; i++) {
1409 			status = match_convert(&match[i], match_ll_ptr[i], 1);
1410 			if (status)
1411 				goto fail;
1412 		}
1413 
1414 		/* Rule action conversion */
1415 		for (i = 0; i < *n_rules; i++) {
1416 			status = action_convert(a, &action[i], action_ll_ptr[i]);
1417 			if (status)
1418 				goto fail;
1419 		}
1420 
1421 		/* Add rule (match, action) to table */
1422 		if (bulk) {
1423 			status = rte_pipeline_table_entry_add_bulk(p->p,
1424 				table_id,
1425 				match_ll_ptr,
1426 				action_ll_ptr,
1427 				*n_rules,
1428 				found,
1429 				entries_ptr);
1430 			if (status)
1431 				*n_rules = 0;
1432 		} else {
1433 			for (i = 0; i < *n_rules; i++) {
1434 				status = rte_pipeline_table_entry_add(p->p,
1435 					table_id,
1436 					match_ll_ptr[i],
1437 					action_ll_ptr[i],
1438 					&found[i],
1439 					&entries_ptr[i]);
1440 				if (status) {
1441 					*n_rules = i;
1442 					break;
1443 				}
1444 			}
1445 		}
1446 
1447 		/* Free */
1448 		free(found);
1449 		free(action_ll_ptr);
1450 		free(match_ll_ptr);
1451 		free(action_ll);
1452 		free(match_ll);
1453 
1454 		return status;
1455 
1456 fail:
1457 		free(found);
1458 		free(action_ll_ptr);
1459 		free(match_ll_ptr);
1460 		free(action_ll);
1461 		free(match_ll);
1462 
1463 		*n_rules = 0;
1464 		return -1;
1465 	}
1466 
1467 	/* Allocate request */
1468 	req = pipeline_msg_alloc();
1469 	if (req == NULL)
1470 		return -1;
1471 
1472 	/* Write request */
1473 	req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1474 	req->id = table_id;
1475 	req->table_rule_add_bulk.match = match;
1476 	req->table_rule_add_bulk.action = action;
1477 	req->table_rule_add_bulk.data = data;
1478 	req->table_rule_add_bulk.n_rules = *n_rules;
1479 	req->table_rule_add_bulk.bulk =
1480 		(p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1481 
1482 	/* Send request and wait for response */
1483 	rsp = pipeline_msg_send_recv(p, req);
1484 	if (rsp == NULL)
1485 		return -1;
1486 
1487 	/* Read response */
1488 	status = rsp->status;
1489 	if (status == 0)
1490 		*n_rules = rsp->table_rule_add_bulk.n_rules;
1491 
1492 	/* Free response */
1493 	pipeline_msg_free(rsp);
1494 
1495 	return status;
1496 }
1497 
1498 int
1499 softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
1500 	const char *pipeline_name,
1501 	uint32_t table_id,
1502 	struct softnic_table_rule_match *match)
1503 {
1504 	struct pipeline *p;
1505 	struct pipeline_msg_req *req;
1506 	struct pipeline_msg_rsp *rsp;
1507 	int status;
1508 
1509 	/* Check input params */
1510 	if (pipeline_name == NULL ||
1511 		match == NULL)
1512 		return -1;
1513 
1514 	p = softnic_pipeline_find(softnic, pipeline_name);
1515 	if (p == NULL ||
1516 		table_id >= p->n_tables ||
1517 		match_check(match, p, table_id))
1518 		return -1;
1519 
1520 	if (!pipeline_is_running(p)) {
1521 		union table_rule_match_low_level match_ll;
1522 		int key_found;
1523 
1524 		status = match_convert(match, &match_ll, 0);
1525 		if (status)
1526 			return -1;
1527 
1528 		status = rte_pipeline_table_entry_delete(p->p,
1529 				table_id,
1530 				&match_ll,
1531 				&key_found,
1532 				NULL);
1533 
1534 		return status;
1535 	}
1536 
1537 	/* Allocate request */
1538 	req = pipeline_msg_alloc();
1539 	if (req == NULL)
1540 		return -1;
1541 
1542 	/* Write request */
1543 	req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1544 	req->id = table_id;
1545 	memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1546 
1547 	/* Send request and wait for response */
1548 	rsp = pipeline_msg_send_recv(p, req);
1549 	if (rsp == NULL)
1550 		return -1;
1551 
1552 	/* Read response */
1553 	status = rsp->status;
1554 
1555 	/* Free response */
1556 	pipeline_msg_free(rsp);
1557 
1558 	return status;
1559 }
1560 
1561 int
1562 softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
1563 	const char *pipeline_name,
1564 	uint32_t table_id)
1565 {
1566 	struct pipeline *p;
1567 	struct pipeline_msg_req *req;
1568 	struct pipeline_msg_rsp *rsp;
1569 	int status;
1570 
1571 	/* Check input params */
1572 	if (pipeline_name == NULL)
1573 		return -1;
1574 
1575 	p = softnic_pipeline_find(softnic, pipeline_name);
1576 	if (p == NULL ||
1577 		table_id >= p->n_tables)
1578 		return -1;
1579 
1580 	if (!pipeline_is_running(p)) {
1581 		status = rte_pipeline_table_default_entry_delete(p->p,
1582 			table_id,
1583 			NULL);
1584 
1585 		return status;
1586 	}
1587 
1588 	/* Allocate request */
1589 	req = pipeline_msg_alloc();
1590 	if (req == NULL)
1591 		return -1;
1592 
1593 	/* Write request */
1594 	req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1595 	req->id = table_id;
1596 
1597 	/* Send request and wait for response */
1598 	rsp = pipeline_msg_send_recv(p, req);
1599 	if (rsp == NULL)
1600 		return -1;
1601 
1602 	/* Read response */
1603 	status = rsp->status;
1604 
1605 	/* Free response */
1606 	pipeline_msg_free(rsp);
1607 
1608 	return status;
1609 }
1610 
1611 int
1612 softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic,
1613 	const char *pipeline_name,
1614 	uint32_t table_id,
1615 	void *data,
1616 	struct rte_table_action_stats_counters *stats,
1617 	int clear)
1618 {
1619 	struct pipeline *p;
1620 	struct pipeline_msg_req *req;
1621 	struct pipeline_msg_rsp *rsp;
1622 	int status;
1623 
1624 	/* Check input params */
1625 	if (pipeline_name == NULL ||
1626 		data == NULL ||
1627 		stats == NULL)
1628 		return -1;
1629 
1630 	p = softnic_pipeline_find(softnic, pipeline_name);
1631 	if (p == NULL ||
1632 		table_id >= p->n_tables)
1633 		return -1;
1634 
1635 	if (!pipeline_is_running(p)) {
1636 		struct rte_table_action *a = p->table[table_id].a;
1637 
1638 		status = rte_table_action_stats_read(a,
1639 			data,
1640 			stats,
1641 			clear);
1642 
1643 		return status;
1644 	}
1645 
1646 	/* Allocate request */
1647 	req = pipeline_msg_alloc();
1648 	if (req == NULL)
1649 		return -1;
1650 
1651 	/* Write request */
1652 	req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
1653 	req->id = table_id;
1654 	req->table_rule_stats_read.data = data;
1655 	req->table_rule_stats_read.clear = clear;
1656 
1657 	/* Send request and wait for response */
1658 	rsp = pipeline_msg_send_recv(p, req);
1659 	if (rsp == NULL)
1660 		return -1;
1661 
1662 	/* Read response */
1663 	status = rsp->status;
1664 	if (status)
1665 		memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
1666 
1667 	/* Free response */
1668 	pipeline_msg_free(rsp);
1669 
1670 	return status;
1671 }
1672 
1673 int
1674 softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic,
1675 	const char *pipeline_name,
1676 	uint32_t table_id,
1677 	uint32_t meter_profile_id,
1678 	struct rte_table_action_meter_profile *profile)
1679 {
1680 	struct pipeline *p;
1681 	struct pipeline_msg_req *req;
1682 	struct pipeline_msg_rsp *rsp;
1683 	struct softnic_table *table;
1684 	struct softnic_table_meter_profile *mp;
1685 	int status;
1686 
1687 	/* Check input params */
1688 	if (pipeline_name == NULL ||
1689 		profile == NULL)
1690 		return -1;
1691 
1692 	p = softnic_pipeline_find(softnic, pipeline_name);
1693 	if (p == NULL ||
1694 		table_id >= p->n_tables)
1695 		return -1;
1696 
1697 	table = &p->table[table_id];
1698 	mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id);
1699 	if (mp)
1700 		return -1;
1701 
1702 	/* Resource Allocation */
1703 	mp = calloc(1, sizeof(struct softnic_table_meter_profile));
1704 	if (mp == NULL)
1705 		return -1;
1706 
1707 	mp->meter_profile_id = meter_profile_id;
1708 	memcpy(&mp->profile, profile, sizeof(mp->profile));
1709 
1710 	if (!pipeline_is_running(p)) {
1711 		status = rte_table_action_meter_profile_add(table->a,
1712 			meter_profile_id,
1713 			profile);
1714 		if (status) {
1715 			free(mp);
1716 			return status;
1717 		}
1718 
1719 		/* Add profile to the table. */
1720 		TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1721 
1722 		return status;
1723 	}
1724 
1725 	/* Allocate request */
1726 	req = pipeline_msg_alloc();
1727 	if (req == NULL) {
1728 		free(mp);
1729 		return -1;
1730 	}
1731 
1732 	/* Write request */
1733 	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
1734 	req->id = table_id;
1735 	req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
1736 	memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
1737 
1738 	/* Send request and wait for response */
1739 	rsp = pipeline_msg_send_recv(p, req);
1740 	if (rsp == NULL) {
1741 		free(mp);
1742 		return -1;
1743 	}
1744 
1745 	/* Read response */
1746 	status = rsp->status;
1747 	if (status == 0)
1748 		TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1749 	else
1750 		free(mp);
1751 
1752 	/* Free response */
1753 	pipeline_msg_free(rsp);
1754 
1755 	return status;
1756 }
1757 
1758 int
1759 softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *softnic,
1760 	const char *pipeline_name,
1761 	uint32_t table_id,
1762 	uint32_t meter_profile_id)
1763 {
1764 	struct pipeline *p;
1765 	struct pipeline_msg_req *req;
1766 	struct pipeline_msg_rsp *rsp;
1767 	int status;
1768 
1769 	/* Check input params */
1770 	if (pipeline_name == NULL)
1771 		return -1;
1772 
1773 	p = softnic_pipeline_find(softnic, pipeline_name);
1774 	if (p == NULL ||
1775 		table_id >= p->n_tables)
1776 		return -1;
1777 
1778 	if (!pipeline_is_running(p)) {
1779 		struct rte_table_action *a = p->table[table_id].a;
1780 
1781 		status = rte_table_action_meter_profile_delete(a,
1782 				meter_profile_id);
1783 
1784 		return status;
1785 	}
1786 
1787 	/* Allocate request */
1788 	req = pipeline_msg_alloc();
1789 	if (req == NULL)
1790 		return -1;
1791 
1792 	/* Write request */
1793 	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
1794 	req->id = table_id;
1795 	req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
1796 
1797 	/* Send request and wait for response */
1798 	rsp = pipeline_msg_send_recv(p, req);
1799 	if (rsp == NULL)
1800 		return -1;
1801 
1802 	/* Read response */
1803 	status = rsp->status;
1804 
1805 	/* Free response */
1806 	pipeline_msg_free(rsp);
1807 
1808 	return status;
1809 }
1810 
1811 int
1812 softnic_pipeline_table_rule_mtr_read(struct pmd_internals *softnic,
1813 	const char *pipeline_name,
1814 	uint32_t table_id,
1815 	void *data,
1816 	uint32_t tc_mask,
1817 	struct rte_table_action_mtr_counters *stats,
1818 	int clear)
1819 {
1820 	struct pipeline *p;
1821 	struct pipeline_msg_req *req;
1822 	struct pipeline_msg_rsp *rsp;
1823 	int status;
1824 
1825 	/* Check input params */
1826 	if (pipeline_name == NULL ||
1827 		data == NULL ||
1828 		stats == NULL)
1829 		return -1;
1830 
1831 	p = softnic_pipeline_find(softnic, pipeline_name);
1832 	if (p == NULL ||
1833 		table_id >= p->n_tables)
1834 		return -1;
1835 
1836 	if (!pipeline_is_running(p)) {
1837 		struct rte_table_action *a = p->table[table_id].a;
1838 
1839 		status = rte_table_action_meter_read(a,
1840 				data,
1841 				tc_mask,
1842 				stats,
1843 				clear);
1844 
1845 		return status;
1846 	}
1847 
1848 	/* Allocate request */
1849 	req = pipeline_msg_alloc();
1850 	if (req == NULL)
1851 		return -1;
1852 
1853 	/* Write request */
1854 	req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
1855 	req->id = table_id;
1856 	req->table_rule_mtr_read.data = data;
1857 	req->table_rule_mtr_read.tc_mask = tc_mask;
1858 	req->table_rule_mtr_read.clear = clear;
1859 
1860 	/* Send request and wait for response */
1861 	rsp = pipeline_msg_send_recv(p, req);
1862 	if (rsp == NULL)
1863 		return -1;
1864 
1865 	/* Read response */
1866 	status = rsp->status;
1867 	if (status)
1868 		memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
1869 
1870 	/* Free response */
1871 	pipeline_msg_free(rsp);
1872 
1873 	return status;
1874 }
1875 
1876 int
1877 softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic,
1878 	const char *pipeline_name,
1879 	uint32_t table_id,
1880 	uint64_t dscp_mask,
1881 	struct rte_table_action_dscp_table *dscp_table)
1882 {
1883 	struct pipeline *p;
1884 	struct pipeline_msg_req *req;
1885 	struct pipeline_msg_rsp *rsp;
1886 	int status;
1887 
1888 	/* Check input params */
1889 	if (pipeline_name == NULL ||
1890 		dscp_table == NULL)
1891 		return -1;
1892 
1893 	p = softnic_pipeline_find(softnic, pipeline_name);
1894 	if (p == NULL ||
1895 		table_id >= p->n_tables)
1896 		return -1;
1897 
1898 	if (!pipeline_is_running(p)) {
1899 		struct rte_table_action *a = p->table[table_id].a;
1900 
1901 		status = rte_table_action_dscp_table_update(a,
1902 				dscp_mask,
1903 				dscp_table);
1904 
1905 		/* Update table dscp table */
1906 		if (!status)
1907 			memcpy(&p->table[table_id].dscp_table, dscp_table,
1908 				sizeof(p->table[table_id].dscp_table));
1909 
1910 		return status;
1911 	}
1912 
1913 	/* Allocate request */
1914 	req = pipeline_msg_alloc();
1915 	if (req == NULL)
1916 		return -1;
1917 
1918 	/* Write request */
1919 	req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
1920 	req->id = table_id;
1921 	req->table_dscp_table_update.dscp_mask = dscp_mask;
1922 	memcpy(&req->table_dscp_table_update.dscp_table,
1923 		dscp_table, sizeof(*dscp_table));
1924 
1925 	/* Send request and wait for response */
1926 	rsp = pipeline_msg_send_recv(p, req);
1927 	if (rsp == NULL)
1928 		return -1;
1929 
1930 	/* Read response */
1931 	status = rsp->status;
1932 
1933 	/* Update table dscp table */
1934 	if (!status)
1935 		memcpy(&p->table[table_id].dscp_table, dscp_table,
1936 			sizeof(p->table[table_id].dscp_table));
1937 
1938 	/* Free response */
1939 	pipeline_msg_free(rsp);
1940 
1941 	return status;
1942 }
1943 
1944 int
1945 softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic,
1946 	const char *pipeline_name,
1947 	uint32_t table_id,
1948 	void *data,
1949 	struct rte_table_action_ttl_counters *stats,
1950 	int clear)
1951 {
1952 	struct pipeline *p;
1953 	struct pipeline_msg_req *req;
1954 	struct pipeline_msg_rsp *rsp;
1955 	int status;
1956 
1957 	/* Check input params */
1958 	if (pipeline_name == NULL ||
1959 		data == NULL ||
1960 		stats == NULL)
1961 		return -1;
1962 
1963 	p = softnic_pipeline_find(softnic, pipeline_name);
1964 	if (p == NULL ||
1965 		table_id >= p->n_tables)
1966 		return -1;
1967 
1968 	if (!pipeline_is_running(p)) {
1969 		struct rte_table_action *a = p->table[table_id].a;
1970 
1971 		status = rte_table_action_ttl_read(a,
1972 				data,
1973 				stats,
1974 				clear);
1975 
1976 		return status;
1977 	}
1978 
1979 	/* Allocate request */
1980 	req = pipeline_msg_alloc();
1981 	if (req == NULL)
1982 		return -1;
1983 
1984 	/* Write request */
1985 	req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
1986 	req->id = table_id;
1987 	req->table_rule_ttl_read.data = data;
1988 	req->table_rule_ttl_read.clear = clear;
1989 
1990 	/* Send request and wait for response */
1991 	rsp = pipeline_msg_send_recv(p, req);
1992 	if (rsp == NULL)
1993 		return -1;
1994 
1995 	/* Read response */
1996 	status = rsp->status;
1997 	if (status)
1998 		memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
1999 
2000 	/* Free response */
2001 	pipeline_msg_free(rsp);
2002 
2003 	return status;
2004 }
2005 
2006 /**
2007  * Data plane threads: message handling
2008  */
2009 static inline struct pipeline_msg_req *
2010 pipeline_msg_recv(struct rte_ring *msgq_req)
2011 {
2012 	struct pipeline_msg_req *req;
2013 
2014 	int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
2015 
2016 	if (status != 0)
2017 		return NULL;
2018 
2019 	return req;
2020 }
2021 
2022 static inline void
2023 pipeline_msg_send(struct rte_ring *msgq_rsp,
2024 	struct pipeline_msg_rsp *rsp)
2025 {
2026 	int status;
2027 
2028 	do {
2029 		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
2030 	} while (status == -ENOBUFS);
2031 }
2032 
2033 static struct pipeline_msg_rsp *
2034 pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
2035 	struct pipeline_msg_req *req)
2036 {
2037 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2038 	uint32_t port_id = req->id;
2039 	int clear = req->port_in_stats_read.clear;
2040 
2041 	rsp->status = rte_pipeline_port_in_stats_read(p->p,
2042 		port_id,
2043 		&rsp->port_in_stats_read.stats,
2044 		clear);
2045 
2046 	return rsp;
2047 }
2048 
2049 static struct pipeline_msg_rsp *
2050 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
2051 	struct pipeline_msg_req *req)
2052 {
2053 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2054 	uint32_t port_id = req->id;
2055 
2056 	rsp->status = rte_pipeline_port_in_enable(p->p,
2057 		port_id);
2058 
2059 	return rsp;
2060 }
2061 
2062 static struct pipeline_msg_rsp *
2063 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
2064 	struct pipeline_msg_req *req)
2065 {
2066 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2067 	uint32_t port_id = req->id;
2068 
2069 	rsp->status = rte_pipeline_port_in_disable(p->p,
2070 		port_id);
2071 
2072 	return rsp;
2073 }
2074 
2075 static struct pipeline_msg_rsp *
2076 pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
2077 	struct pipeline_msg_req *req)
2078 {
2079 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2080 	uint32_t port_id = req->id;
2081 	int clear = req->port_out_stats_read.clear;
2082 
2083 	rsp->status = rte_pipeline_port_out_stats_read(p->p,
2084 		port_id,
2085 		&rsp->port_out_stats_read.stats,
2086 		clear);
2087 
2088 	return rsp;
2089 }
2090 
2091 static struct pipeline_msg_rsp *
2092 pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
2093 	struct pipeline_msg_req *req)
2094 {
2095 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2096 	uint32_t port_id = req->id;
2097 	int clear = req->table_stats_read.clear;
2098 
2099 	rsp->status = rte_pipeline_table_stats_read(p->p,
2100 		port_id,
2101 		&rsp->table_stats_read.stats,
2102 		clear);
2103 
2104 	return rsp;
2105 }
2106 
2107 static int
2108 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
2109 {
2110 	if (depth > 128)
2111 		return -1;
2112 
2113 	switch (depth / 32) {
2114 	case 0:
2115 		depth32[0] = depth;
2116 		depth32[1] = 0;
2117 		depth32[2] = 0;
2118 		depth32[3] = 0;
2119 		return 0;
2120 
2121 	case 1:
2122 		depth32[0] = 32;
2123 		depth32[1] = depth - 32;
2124 		depth32[2] = 0;
2125 		depth32[3] = 0;
2126 		return 0;
2127 
2128 	case 2:
2129 		depth32[0] = 32;
2130 		depth32[1] = 32;
2131 		depth32[2] = depth - 64;
2132 		depth32[3] = 0;
2133 		return 0;
2134 
2135 	case 3:
2136 		depth32[0] = 32;
2137 		depth32[1] = 32;
2138 		depth32[2] = 32;
2139 		depth32[3] = depth - 96;
2140 		return 0;
2141 
2142 	case 4:
2143 		depth32[0] = 32;
2144 		depth32[1] = 32;
2145 		depth32[2] = 32;
2146 		depth32[3] = 32;
2147 		return 0;
2148 
2149 	default:
2150 		return -1;
2151 	}
2152 }
2153 
2154 static int
2155 match_convert(struct softnic_table_rule_match *mh,
2156 	union table_rule_match_low_level *ml,
2157 	int add)
2158 {
2159 	memset(ml, 0, sizeof(*ml));
2160 
2161 	switch (mh->match_type) {
2162 	case TABLE_ACL:
2163 		if (mh->match.acl.ip_version)
2164 			if (add) {
2165 				ml->acl_add.field_value[0].value.u8 =
2166 					mh->match.acl.proto;
2167 				ml->acl_add.field_value[0].mask_range.u8 =
2168 					mh->match.acl.proto_mask;
2169 
2170 				ml->acl_add.field_value[1].value.u32 =
2171 					mh->match.acl.ipv4.sa;
2172 				ml->acl_add.field_value[1].mask_range.u32 =
2173 					mh->match.acl.sa_depth;
2174 
2175 				ml->acl_add.field_value[2].value.u32 =
2176 					mh->match.acl.ipv4.da;
2177 				ml->acl_add.field_value[2].mask_range.u32 =
2178 					mh->match.acl.da_depth;
2179 
2180 				ml->acl_add.field_value[3].value.u16 =
2181 					mh->match.acl.sp0;
2182 				ml->acl_add.field_value[3].mask_range.u16 =
2183 					mh->match.acl.sp1;
2184 
2185 				ml->acl_add.field_value[4].value.u16 =
2186 					mh->match.acl.dp0;
2187 				ml->acl_add.field_value[4].mask_range.u16 =
2188 					mh->match.acl.dp1;
2189 
2190 				ml->acl_add.priority =
2191 					(int32_t)mh->match.acl.priority;
2192 			} else {
2193 				ml->acl_delete.field_value[0].value.u8 =
2194 					mh->match.acl.proto;
2195 				ml->acl_delete.field_value[0].mask_range.u8 =
2196 					mh->match.acl.proto_mask;
2197 
2198 				ml->acl_delete.field_value[1].value.u32 =
2199 					mh->match.acl.ipv4.sa;
2200 				ml->acl_delete.field_value[1].mask_range.u32 =
2201 					mh->match.acl.sa_depth;
2202 
2203 				ml->acl_delete.field_value[2].value.u32 =
2204 					mh->match.acl.ipv4.da;
2205 				ml->acl_delete.field_value[2].mask_range.u32 =
2206 					mh->match.acl.da_depth;
2207 
2208 				ml->acl_delete.field_value[3].value.u16 =
2209 					mh->match.acl.sp0;
2210 				ml->acl_delete.field_value[3].mask_range.u16 =
2211 					mh->match.acl.sp1;
2212 
2213 				ml->acl_delete.field_value[4].value.u16 =
2214 					mh->match.acl.dp0;
2215 				ml->acl_delete.field_value[4].mask_range.u16 =
2216 					mh->match.acl.dp1;
2217 			}
2218 		else
2219 			if (add) {
2220 				uint32_t *sa32 =
2221 					(uint32_t *)mh->match.acl.ipv6.sa;
2222 				uint32_t *da32 =
2223 					(uint32_t *)mh->match.acl.ipv6.da;
2224 				uint32_t sa32_depth[4], da32_depth[4];
2225 				int status;
2226 
2227 				status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2228 					sa32_depth);
2229 				if (status)
2230 					return status;
2231 
2232 				status = match_convert_ipv6_depth(
2233 					mh->match.acl.da_depth,
2234 					da32_depth);
2235 				if (status)
2236 					return status;
2237 
2238 				ml->acl_add.field_value[0].value.u8 =
2239 					mh->match.acl.proto;
2240 				ml->acl_add.field_value[0].mask_range.u8 =
2241 					mh->match.acl.proto_mask;
2242 
2243 				ml->acl_add.field_value[1].value.u32 =
2244 					rte_be_to_cpu_32(sa32[0]);
2245 				ml->acl_add.field_value[1].mask_range.u32 =
2246 					sa32_depth[0];
2247 				ml->acl_add.field_value[2].value.u32 =
2248 					rte_be_to_cpu_32(sa32[1]);
2249 				ml->acl_add.field_value[2].mask_range.u32 =
2250 					sa32_depth[1];
2251 				ml->acl_add.field_value[3].value.u32 =
2252 					rte_be_to_cpu_32(sa32[2]);
2253 				ml->acl_add.field_value[3].mask_range.u32 =
2254 					sa32_depth[2];
2255 				ml->acl_add.field_value[4].value.u32 =
2256 					rte_be_to_cpu_32(sa32[3]);
2257 				ml->acl_add.field_value[4].mask_range.u32 =
2258 					sa32_depth[3];
2259 
2260 				ml->acl_add.field_value[5].value.u32 =
2261 					rte_be_to_cpu_32(da32[0]);
2262 				ml->acl_add.field_value[5].mask_range.u32 =
2263 					da32_depth[0];
2264 				ml->acl_add.field_value[6].value.u32 =
2265 					rte_be_to_cpu_32(da32[1]);
2266 				ml->acl_add.field_value[6].mask_range.u32 =
2267 					da32_depth[1];
2268 				ml->acl_add.field_value[7].value.u32 =
2269 					rte_be_to_cpu_32(da32[2]);
2270 				ml->acl_add.field_value[7].mask_range.u32 =
2271 					da32_depth[2];
2272 				ml->acl_add.field_value[8].value.u32 =
2273 					rte_be_to_cpu_32(da32[3]);
2274 				ml->acl_add.field_value[8].mask_range.u32 =
2275 					da32_depth[3];
2276 
2277 				ml->acl_add.field_value[9].value.u16 =
2278 					mh->match.acl.sp0;
2279 				ml->acl_add.field_value[9].mask_range.u16 =
2280 					mh->match.acl.sp1;
2281 
2282 				ml->acl_add.field_value[10].value.u16 =
2283 					mh->match.acl.dp0;
2284 				ml->acl_add.field_value[10].mask_range.u16 =
2285 					mh->match.acl.dp1;
2286 
2287 				ml->acl_add.priority =
2288 					(int32_t)mh->match.acl.priority;
2289 			} else {
2290 				uint32_t *sa32 =
2291 					(uint32_t *)mh->match.acl.ipv6.sa;
2292 				uint32_t *da32 =
2293 					(uint32_t *)mh->match.acl.ipv6.da;
2294 				uint32_t sa32_depth[4], da32_depth[4];
2295 				int status;
2296 
2297 				status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2298 					sa32_depth);
2299 				if (status)
2300 					return status;
2301 
2302 				status = match_convert_ipv6_depth(mh->match.acl.da_depth,
2303 					da32_depth);
2304 				if (status)
2305 					return status;
2306 
2307 				ml->acl_delete.field_value[0].value.u8 =
2308 					mh->match.acl.proto;
2309 				ml->acl_delete.field_value[0].mask_range.u8 =
2310 					mh->match.acl.proto_mask;
2311 
2312 				ml->acl_delete.field_value[1].value.u32 =
2313 					rte_be_to_cpu_32(sa32[0]);
2314 				ml->acl_delete.field_value[1].mask_range.u32 =
2315 					sa32_depth[0];
2316 				ml->acl_delete.field_value[2].value.u32 =
2317 					rte_be_to_cpu_32(sa32[1]);
2318 				ml->acl_delete.field_value[2].mask_range.u32 =
2319 					sa32_depth[1];
2320 				ml->acl_delete.field_value[3].value.u32 =
2321 					rte_be_to_cpu_32(sa32[2]);
2322 				ml->acl_delete.field_value[3].mask_range.u32 =
2323 					sa32_depth[2];
2324 				ml->acl_delete.field_value[4].value.u32 =
2325 					rte_be_to_cpu_32(sa32[3]);
2326 				ml->acl_delete.field_value[4].mask_range.u32 =
2327 					sa32_depth[3];
2328 
2329 				ml->acl_delete.field_value[5].value.u32 =
2330 					rte_be_to_cpu_32(da32[0]);
2331 				ml->acl_delete.field_value[5].mask_range.u32 =
2332 					da32_depth[0];
2333 				ml->acl_delete.field_value[6].value.u32 =
2334 					rte_be_to_cpu_32(da32[1]);
2335 				ml->acl_delete.field_value[6].mask_range.u32 =
2336 					da32_depth[1];
2337 				ml->acl_delete.field_value[7].value.u32 =
2338 					rte_be_to_cpu_32(da32[2]);
2339 				ml->acl_delete.field_value[7].mask_range.u32 =
2340 					da32_depth[2];
2341 				ml->acl_delete.field_value[8].value.u32 =
2342 					rte_be_to_cpu_32(da32[3]);
2343 				ml->acl_delete.field_value[8].mask_range.u32 =
2344 					da32_depth[3];
2345 
2346 				ml->acl_delete.field_value[9].value.u16 =
2347 					mh->match.acl.sp0;
2348 				ml->acl_delete.field_value[9].mask_range.u16 =
2349 					mh->match.acl.sp1;
2350 
2351 				ml->acl_delete.field_value[10].value.u16 =
2352 					mh->match.acl.dp0;
2353 				ml->acl_delete.field_value[10].mask_range.u16 =
2354 					mh->match.acl.dp1;
2355 			}
2356 		return 0;
2357 
2358 	case TABLE_ARRAY:
2359 		ml->array.pos = mh->match.array.pos;
2360 		return 0;
2361 
2362 	case TABLE_HASH:
2363 		memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
2364 		return 0;
2365 
2366 	case TABLE_LPM:
2367 		if (mh->match.lpm.ip_version) {
2368 			ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
2369 			ml->lpm_ipv4.depth = mh->match.lpm.depth;
2370 		} else {
2371 			memcpy(ml->lpm_ipv6.ip,
2372 				mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
2373 			ml->lpm_ipv6.depth = mh->match.lpm.depth;
2374 		}
2375 
2376 		return 0;
2377 
2378 	default:
2379 		return -1;
2380 	}
2381 }
2382 
2383 static int
2384 action_convert(struct rte_table_action *a,
2385 	struct softnic_table_rule_action *action,
2386 	struct rte_pipeline_table_entry *data)
2387 {
2388 	int status;
2389 
2390 	/* Apply actions */
2391 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
2392 		status = rte_table_action_apply(a,
2393 			data,
2394 			RTE_TABLE_ACTION_FWD,
2395 			&action->fwd);
2396 
2397 		if (status)
2398 			return status;
2399 	}
2400 
2401 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2402 		status = rte_table_action_apply(a,
2403 			data,
2404 			RTE_TABLE_ACTION_LB,
2405 			&action->lb);
2406 
2407 		if (status)
2408 			return status;
2409 	}
2410 
2411 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2412 		status = rte_table_action_apply(a,
2413 			data,
2414 			RTE_TABLE_ACTION_MTR,
2415 			&action->mtr);
2416 
2417 		if (status)
2418 			return status;
2419 	}
2420 
2421 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2422 		status = rte_table_action_apply(a,
2423 			data,
2424 			RTE_TABLE_ACTION_TM,
2425 			&action->tm);
2426 
2427 		if (status)
2428 			return status;
2429 	}
2430 
2431 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2432 		status = rte_table_action_apply(a,
2433 			data,
2434 			RTE_TABLE_ACTION_ENCAP,
2435 			&action->encap);
2436 
2437 		if (status)
2438 			return status;
2439 	}
2440 
2441 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2442 		status = rte_table_action_apply(a,
2443 			data,
2444 			RTE_TABLE_ACTION_NAT,
2445 			&action->nat);
2446 
2447 		if (status)
2448 			return status;
2449 	}
2450 
2451 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2452 		status = rte_table_action_apply(a,
2453 			data,
2454 			RTE_TABLE_ACTION_TTL,
2455 			&action->ttl);
2456 
2457 		if (status)
2458 			return status;
2459 	}
2460 
2461 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2462 		status = rte_table_action_apply(a,
2463 			data,
2464 			RTE_TABLE_ACTION_STATS,
2465 			&action->stats);
2466 
2467 		if (status)
2468 			return status;
2469 	}
2470 
2471 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2472 		status = rte_table_action_apply(a,
2473 			data,
2474 			RTE_TABLE_ACTION_TIME,
2475 			&action->time);
2476 
2477 		if (status)
2478 			return status;
2479 	}
2480 
2481 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
2482 		status = rte_table_action_apply(a,
2483 			data,
2484 			RTE_TABLE_ACTION_TAG,
2485 			&action->tag);
2486 
2487 		if (status)
2488 			return status;
2489 	}
2490 
2491 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
2492 		status = rte_table_action_apply(a,
2493 			data,
2494 			RTE_TABLE_ACTION_DECAP,
2495 			&action->decap);
2496 
2497 		if (status)
2498 			return status;
2499 	}
2500 
2501 	return 0;
2502 }
2503 
2504 static struct pipeline_msg_rsp *
2505 pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
2506 	struct pipeline_msg_req *req)
2507 {
2508 	union table_rule_match_low_level match_ll;
2509 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2510 	struct softnic_table_rule_match *match = &req->table_rule_add.match;
2511 	struct softnic_table_rule_action *action = &req->table_rule_add.action;
2512 	struct rte_pipeline_table_entry *data_in, *data_out;
2513 	uint32_t table_id = req->id;
2514 	int key_found, status;
2515 	struct rte_table_action *a = p->table_data[table_id].a;
2516 
2517 	/* Apply actions */
2518 	memset(p->buffer, 0, sizeof(p->buffer));
2519 	data_in = (struct rte_pipeline_table_entry *)p->buffer;
2520 
2521 	status = match_convert(match, &match_ll, 1);
2522 	if (status) {
2523 		rsp->status = -1;
2524 		return rsp;
2525 	}
2526 
2527 	status = action_convert(a, action, data_in);
2528 	if (status) {
2529 		rsp->status = -1;
2530 		return rsp;
2531 	}
2532 
2533 	status = rte_pipeline_table_entry_add(p->p,
2534 		table_id,
2535 		&match_ll,
2536 		data_in,
2537 		&key_found,
2538 		&data_out);
2539 	if (status) {
2540 		rsp->status = -1;
2541 		return rsp;
2542 	}
2543 
2544 	/* Write response */
2545 	rsp->status = 0;
2546 	rsp->table_rule_add.data = data_out;
2547 
2548 	return rsp;
2549 }
2550 
2551 static struct pipeline_msg_rsp *
2552 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
2553 	struct pipeline_msg_req *req)
2554 {
2555 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2556 	struct softnic_table_rule_action *action = &req->table_rule_add_default.action;
2557 	struct rte_pipeline_table_entry *data_in, *data_out;
2558 	uint32_t table_id = req->id;
2559 	int status;
2560 
2561 	/* Apply actions */
2562 	memset(p->buffer, 0, sizeof(p->buffer));
2563 	data_in = (struct rte_pipeline_table_entry *)p->buffer;
2564 
2565 	data_in->action = action->fwd.action;
2566 	if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
2567 		data_in->port_id = action->fwd.id;
2568 	if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
2569 		data_in->table_id = action->fwd.id;
2570 
2571 	/* Add default rule to table */
2572 	status = rte_pipeline_table_default_entry_add(p->p,
2573 		table_id,
2574 		data_in,
2575 		&data_out);
2576 	if (status) {
2577 		rsp->status = -1;
2578 		return rsp;
2579 	}
2580 
2581 	/* Write response */
2582 	rsp->status = 0;
2583 	rsp->table_rule_add_default.data = data_out;
2584 
2585 	return rsp;
2586 }
2587 
2588 static struct pipeline_msg_rsp *
2589 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
2590 	struct pipeline_msg_req *req)
2591 {
2592 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2593 
2594 	uint32_t table_id = req->id;
2595 	struct softnic_table_rule_match *match = req->table_rule_add_bulk.match;
2596 	struct softnic_table_rule_action *action = req->table_rule_add_bulk.action;
2597 	struct rte_pipeline_table_entry **data =
2598 		(struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
2599 	uint32_t n_rules = req->table_rule_add_bulk.n_rules;
2600 	uint32_t bulk = req->table_rule_add_bulk.bulk;
2601 
2602 	struct rte_table_action *a = p->table_data[table_id].a;
2603 	union table_rule_match_low_level *match_ll;
2604 	uint8_t *action_ll;
2605 	void **match_ll_ptr;
2606 	struct rte_pipeline_table_entry **action_ll_ptr;
2607 	int *found, status;
2608 	uint32_t i;
2609 
2610 	/* Memory allocation */
2611 	match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
2612 	action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
2613 	match_ll_ptr = calloc(n_rules, sizeof(void *));
2614 	action_ll_ptr =
2615 		calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
2616 	found = calloc(n_rules, sizeof(int));
2617 
2618 	if (match_ll == NULL ||
2619 		action_ll == NULL ||
2620 		match_ll_ptr == NULL ||
2621 		action_ll_ptr == NULL ||
2622 		found == NULL)
2623 		goto fail;
2624 
2625 	for (i = 0; i < n_rules; i++) {
2626 		match_ll_ptr[i] = (void *)&match_ll[i];
2627 		action_ll_ptr[i] =
2628 			(struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
2629 	}
2630 
2631 	/* Rule match conversion */
2632 	for (i = 0; i < n_rules; i++) {
2633 		status = match_convert(&match[i], match_ll_ptr[i], 1);
2634 		if (status)
2635 			goto fail;
2636 	}
2637 
2638 	/* Rule action conversion */
2639 	for (i = 0; i < n_rules; i++) {
2640 		status = action_convert(a, &action[i], action_ll_ptr[i]);
2641 		if (status)
2642 			goto fail;
2643 	}
2644 
2645 	/* Add rule (match, action) to table */
2646 	if (bulk) {
2647 		status = rte_pipeline_table_entry_add_bulk(p->p,
2648 			table_id,
2649 			match_ll_ptr,
2650 			action_ll_ptr,
2651 			n_rules,
2652 			found,
2653 			data);
2654 		if (status)
2655 			n_rules = 0;
2656 	} else {
2657 		for (i = 0; i < n_rules; i++) {
2658 			status = rte_pipeline_table_entry_add(p->p,
2659 				table_id,
2660 				match_ll_ptr[i],
2661 				action_ll_ptr[i],
2662 				&found[i],
2663 				&data[i]);
2664 			if (status) {
2665 				n_rules = i;
2666 				break;
2667 			}
2668 		}
2669 	}
2670 
2671 	/* Write response */
2672 	rsp->status = 0;
2673 	rsp->table_rule_add_bulk.n_rules = n_rules;
2674 
2675 	/* Free */
2676 	free(found);
2677 	free(action_ll_ptr);
2678 	free(match_ll_ptr);
2679 	free(action_ll);
2680 	free(match_ll);
2681 
2682 	return rsp;
2683 
2684 fail:
2685 	free(found);
2686 	free(action_ll_ptr);
2687 	free(match_ll_ptr);
2688 	free(action_ll);
2689 	free(match_ll);
2690 
2691 	rsp->status = -1;
2692 	rsp->table_rule_add_bulk.n_rules = 0;
2693 	return rsp;
2694 }
2695 
2696 static struct pipeline_msg_rsp *
2697 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
2698 	struct pipeline_msg_req *req)
2699 {
2700 	union table_rule_match_low_level match_ll;
2701 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2702 	struct softnic_table_rule_match *match = &req->table_rule_delete.match;
2703 	uint32_t table_id = req->id;
2704 	int key_found, status;
2705 
2706 	status = match_convert(match, &match_ll, 0);
2707 	if (status) {
2708 		rsp->status = -1;
2709 		return rsp;
2710 	}
2711 
2712 	rsp->status = rte_pipeline_table_entry_delete(p->p,
2713 		table_id,
2714 		&match_ll,
2715 		&key_found,
2716 		NULL);
2717 
2718 	return rsp;
2719 }
2720 
2721 static struct pipeline_msg_rsp *
2722 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
2723 	struct pipeline_msg_req *req)
2724 {
2725 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2726 	uint32_t table_id = req->id;
2727 
2728 	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
2729 		table_id,
2730 		NULL);
2731 
2732 	return rsp;
2733 }
2734 
2735 static struct pipeline_msg_rsp *
2736 pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
2737 	struct pipeline_msg_req *req)
2738 {
2739 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2740 	uint32_t table_id = req->id;
2741 	void *data = req->table_rule_stats_read.data;
2742 	int clear = req->table_rule_stats_read.clear;
2743 	struct rte_table_action *a = p->table_data[table_id].a;
2744 
2745 	rsp->status = rte_table_action_stats_read(a,
2746 		data,
2747 		&rsp->table_rule_stats_read.stats,
2748 		clear);
2749 
2750 	return rsp;
2751 }
2752 
2753 static struct pipeline_msg_rsp *
2754 pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
2755 	struct pipeline_msg_req *req)
2756 {
2757 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2758 	uint32_t table_id = req->id;
2759 	uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
2760 	struct rte_table_action_meter_profile *profile =
2761 		&req->table_mtr_profile_add.profile;
2762 	struct rte_table_action *a = p->table_data[table_id].a;
2763 
2764 	rsp->status = rte_table_action_meter_profile_add(a,
2765 		meter_profile_id,
2766 		profile);
2767 
2768 	return rsp;
2769 }
2770 
2771 static struct pipeline_msg_rsp *
2772 pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
2773 	struct pipeline_msg_req *req)
2774 {
2775 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2776 	uint32_t table_id = req->id;
2777 	uint32_t meter_profile_id =
2778 		req->table_mtr_profile_delete.meter_profile_id;
2779 	struct rte_table_action *a = p->table_data[table_id].a;
2780 
2781 	rsp->status = rte_table_action_meter_profile_delete(a,
2782 		meter_profile_id);
2783 
2784 	return rsp;
2785 }
2786 
2787 static struct pipeline_msg_rsp *
2788 pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
2789 	struct pipeline_msg_req *req)
2790 {
2791 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2792 	uint32_t table_id = req->id;
2793 	void *data = req->table_rule_mtr_read.data;
2794 	uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
2795 	int clear = req->table_rule_mtr_read.clear;
2796 	struct rte_table_action *a = p->table_data[table_id].a;
2797 
2798 	rsp->status = rte_table_action_meter_read(a,
2799 		data,
2800 		tc_mask,
2801 		&rsp->table_rule_mtr_read.stats,
2802 		clear);
2803 
2804 	return rsp;
2805 }
2806 
2807 static struct pipeline_msg_rsp *
2808 pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
2809 	struct pipeline_msg_req *req)
2810 {
2811 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2812 	uint32_t table_id = req->id;
2813 	uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
2814 	struct rte_table_action_dscp_table *dscp_table =
2815 		&req->table_dscp_table_update.dscp_table;
2816 	struct rte_table_action *a = p->table_data[table_id].a;
2817 
2818 	rsp->status = rte_table_action_dscp_table_update(a,
2819 		dscp_mask,
2820 		dscp_table);
2821 
2822 	return rsp;
2823 }
2824 
2825 static struct pipeline_msg_rsp *
2826 pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
2827 	struct pipeline_msg_req *req)
2828 {
2829 	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2830 	uint32_t table_id = req->id;
2831 	void *data = req->table_rule_ttl_read.data;
2832 	int clear = req->table_rule_ttl_read.clear;
2833 	struct rte_table_action *a = p->table_data[table_id].a;
2834 
2835 	rsp->status = rte_table_action_ttl_read(a,
2836 		data,
2837 		&rsp->table_rule_ttl_read.stats,
2838 		clear);
2839 
2840 	return rsp;
2841 }
2842 
2843 static void
2844 pipeline_msg_handle(struct pipeline_data *p)
2845 {
2846 	for ( ; ; ) {
2847 		struct pipeline_msg_req *req;
2848 		struct pipeline_msg_rsp *rsp;
2849 
2850 		req = pipeline_msg_recv(p->msgq_req);
2851 		if (req == NULL)
2852 			break;
2853 
2854 		switch (req->type) {
2855 		case PIPELINE_REQ_PORT_IN_STATS_READ:
2856 			rsp = pipeline_msg_handle_port_in_stats_read(p, req);
2857 			break;
2858 
2859 		case PIPELINE_REQ_PORT_IN_ENABLE:
2860 			rsp = pipeline_msg_handle_port_in_enable(p, req);
2861 			break;
2862 
2863 		case PIPELINE_REQ_PORT_IN_DISABLE:
2864 			rsp = pipeline_msg_handle_port_in_disable(p, req);
2865 			break;
2866 
2867 		case PIPELINE_REQ_PORT_OUT_STATS_READ:
2868 			rsp = pipeline_msg_handle_port_out_stats_read(p, req);
2869 			break;
2870 
2871 		case PIPELINE_REQ_TABLE_STATS_READ:
2872 			rsp = pipeline_msg_handle_table_stats_read(p, req);
2873 			break;
2874 
2875 		case PIPELINE_REQ_TABLE_RULE_ADD:
2876 			rsp = pipeline_msg_handle_table_rule_add(p, req);
2877 			break;
2878 
2879 		case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2880 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
2881 			break;
2882 
2883 		case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2884 			rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2885 			break;
2886 
2887 		case PIPELINE_REQ_TABLE_RULE_DELETE:
2888 			rsp = pipeline_msg_handle_table_rule_delete(p, req);
2889 			break;
2890 
2891 		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2892 			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2893 			break;
2894 
2895 		case PIPELINE_REQ_TABLE_RULE_STATS_READ:
2896 			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
2897 			break;
2898 
2899 		case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
2900 			rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
2901 			break;
2902 
2903 		case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
2904 			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
2905 			break;
2906 
2907 		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
2908 			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
2909 			break;
2910 
2911 		case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
2912 			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
2913 			break;
2914 
2915 		case PIPELINE_REQ_TABLE_RULE_TTL_READ:
2916 			rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
2917 			break;
2918 
2919 		default:
2920 			rsp = (struct pipeline_msg_rsp *)req;
2921 			rsp->status = -1;
2922 		}
2923 
2924 		pipeline_msg_send(p->msgq_rsp, rsp);
2925 	}
2926 }
2927 
2928 /**
2929  * Data plane threads: main
2930  */
2931 int
2932 rte_pmd_softnic_run(uint16_t port_id)
2933 {
2934 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
2935 	struct pmd_internals *softnic;
2936 	struct softnic_thread_data *t;
2937 	uint32_t thread_id, j;
2938 
2939 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
2940 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
2941 #endif
2942 
2943 	softnic = dev->data->dev_private;
2944 	thread_id = rte_lcore_id();
2945 	t = &softnic->thread_data[thread_id];
2946 	t->iter++;
2947 
2948 	/* Data Plane */
2949 	for (j = 0; j < t->n_pipelines; j++)
2950 		rte_pipeline_run(t->p[j]);
2951 
2952 	/* Control Plane */
2953 	if ((t->iter & 0xFLLU) == 0) {
2954 		uint64_t time = rte_get_tsc_cycles();
2955 		uint64_t time_next_min = UINT64_MAX;
2956 
2957 		if (time < t->time_next_min)
2958 			return 0;
2959 
2960 		/* Pipeline message queues */
2961 		for (j = 0; j < t->n_pipelines; j++) {
2962 			struct pipeline_data *p =
2963 				&t->pipeline_data[j];
2964 			uint64_t time_next = p->time_next;
2965 
2966 			if (time_next <= time) {
2967 				pipeline_msg_handle(p);
2968 				rte_pipeline_flush(p->p);
2969 				time_next = time + p->timer_period;
2970 				p->time_next = time_next;
2971 			}
2972 
2973 			if (time_next < time_next_min)
2974 				time_next_min = time_next;
2975 		}
2976 
2977 		/* Thread message queues */
2978 		{
2979 			uint64_t time_next = t->time_next;
2980 
2981 			if (time_next <= time) {
2982 				thread_msg_handle(t);
2983 				time_next = time + t->timer_period;
2984 				t->time_next = time_next;
2985 			}
2986 
2987 			if (time_next < time_next_min)
2988 				time_next_min = time_next;
2989 		}
2990 
2991 		t->time_next_min = time_next_min;
2992 	}
2993 
2994 	return 0;
2995 }
2996