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