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