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