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