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