xref: /dpdk/drivers/net/softnic/rte_eth_softnic_pipeline.c (revision 1edccebcccdbe600dc0a3a418fae68336648a87e)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include <rte_common.h>
9 #include <rte_ip.h>
10 #include <rte_tcp.h>
11 
12 #include <rte_string_fns.h>
13 #include <rte_port_ethdev.h>
14 #include <rte_port_ring.h>
15 #include <rte_port_source_sink.h>
16 #include <rte_port_fd.h>
17 #include <rte_port_sched.h>
18 
19 #include <rte_table_acl.h>
20 #include <rte_table_array.h>
21 #include <rte_table_hash.h>
22 #include <rte_table_hash_func.h>
23 #include <rte_table_lpm.h>
24 #include <rte_table_lpm_ipv6.h>
25 #include <rte_table_stub.h>
26 
27 #include "rte_eth_softnic_internals.h"
28 
29 #ifndef PIPELINE_MSGQ_SIZE
30 #define PIPELINE_MSGQ_SIZE                                 64
31 #endif
32 
33 #ifndef TABLE_LPM_NUMBER_TBL8
34 #define TABLE_LPM_NUMBER_TBL8                              256
35 #endif
36 
37 int
38 softnic_pipeline_init(struct pmd_internals *p)
39 {
40 	TAILQ_INIT(&p->pipeline_list);
41 
42 	return 0;
43 }
44 
45 static void
46 softnic_pipeline_table_free(struct softnic_table *table)
47 {
48 	for ( ; ; ) {
49 		struct rte_flow *flow;
50 
51 		flow = TAILQ_FIRST(&table->flows);
52 		if (flow == NULL)
53 			break;
54 
55 		TAILQ_REMOVE(&table->flows, flow, node);
56 		free(flow);
57 	}
58 
59 	for ( ; ; ) {
60 		struct softnic_table_meter_profile *mp;
61 
62 		mp = TAILQ_FIRST(&table->meter_profiles);
63 		if (mp == NULL)
64 			break;
65 
66 		TAILQ_REMOVE(&table->meter_profiles, mp, node);
67 		free(mp);
68 	}
69 }
70 
71 void
72 softnic_pipeline_free(struct pmd_internals *p)
73 {
74 	for ( ; ; ) {
75 		struct pipeline *pipeline;
76 		uint32_t table_id;
77 
78 		pipeline = TAILQ_FIRST(&p->pipeline_list);
79 		if (pipeline == NULL)
80 			break;
81 
82 		TAILQ_REMOVE(&p->pipeline_list, pipeline, node);
83 
84 		for (table_id = 0; table_id < pipeline->n_tables; table_id++) {
85 			struct softnic_table *table =
86 				&pipeline->table[table_id];
87 
88 			softnic_pipeline_table_free(table);
89 		}
90 
91 		rte_ring_free(pipeline->msgq_req);
92 		rte_ring_free(pipeline->msgq_rsp);
93 		rte_pipeline_free(pipeline->p);
94 		free(pipeline);
95 	}
96 }
97 
98 void
99 softnic_pipeline_disable_all(struct pmd_internals *p)
100 {
101 	struct pipeline *pipeline;
102 
103 	TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
104 		if (pipeline->enabled)
105 			softnic_thread_pipeline_disable(p,
106 				pipeline->thread_id,
107 				pipeline->name);
108 }
109 
110 struct pipeline *
111 softnic_pipeline_find(struct pmd_internals *p,
112 	const char *name)
113 {
114 	struct pipeline *pipeline;
115 
116 	if (name == NULL)
117 		return NULL;
118 
119 	TAILQ_FOREACH(pipeline, &p->pipeline_list, node)
120 		if (strcmp(name, pipeline->name) == 0)
121 			return pipeline;
122 
123 	return NULL;
124 }
125 
126 struct pipeline *
127 softnic_pipeline_create(struct pmd_internals *softnic,
128 	const char *name,
129 	struct pipeline_params *params)
130 {
131 	char resource_name[NAME_MAX];
132 	struct rte_pipeline_params pp;
133 	struct pipeline *pipeline;
134 	struct rte_pipeline *p;
135 	struct rte_ring *msgq_req;
136 	struct rte_ring *msgq_rsp;
137 
138 	/* Check input params */
139 	if (name == NULL ||
140 		softnic_pipeline_find(softnic, name) ||
141 		params == NULL ||
142 		params->timer_period_ms == 0)
143 		return NULL;
144 
145 	/* Resource create */
146 	snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
147 		softnic->params.name,
148 		name);
149 
150 	msgq_req = rte_ring_create(resource_name,
151 		PIPELINE_MSGQ_SIZE,
152 		softnic->params.cpu_id,
153 		RING_F_SP_ENQ | RING_F_SC_DEQ);
154 	if (msgq_req == NULL)
155 		return NULL;
156 
157 	snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
158 		softnic->params.name,
159 		name);
160 
161 	msgq_rsp = rte_ring_create(resource_name,
162 		PIPELINE_MSGQ_SIZE,
163 		softnic->params.cpu_id,
164 		RING_F_SP_ENQ | RING_F_SC_DEQ);
165 	if (msgq_rsp == NULL) {
166 		rte_ring_free(msgq_req);
167 		return NULL;
168 	}
169 
170 	snprintf(resource_name, sizeof(resource_name), "%s_%s",
171 		softnic->params.name,
172 		name);
173 
174 	pp.name = resource_name;
175 	pp.socket_id = (int)softnic->params.cpu_id;
176 	pp.offset_port_id = params->offset_port_id;
177 
178 	p = rte_pipeline_create(&pp);
179 	if (p == NULL) {
180 		rte_ring_free(msgq_rsp);
181 		rte_ring_free(msgq_req);
182 		return NULL;
183 	}
184 
185 	/* Node allocation */
186 	pipeline = calloc(1, sizeof(struct pipeline));
187 	if (pipeline == NULL) {
188 		rte_pipeline_free(p);
189 		rte_ring_free(msgq_rsp);
190 		rte_ring_free(msgq_req);
191 		return NULL;
192 	}
193 
194 	/* Node fill in */
195 	strlcpy(pipeline->name, name, sizeof(pipeline->name));
196 	pipeline->p = p;
197 	memcpy(&pipeline->params, params, sizeof(*params));
198 	pipeline->n_ports_in = 0;
199 	pipeline->n_ports_out = 0;
200 	pipeline->n_tables = 0;
201 	pipeline->msgq_req = msgq_req;
202 	pipeline->msgq_rsp = msgq_rsp;
203 	pipeline->timer_period_ms = params->timer_period_ms;
204 	pipeline->enabled = 0;
205 	pipeline->cpu_id = softnic->params.cpu_id;
206 
207 	/* Node add to list */
208 	TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
209 
210 	return pipeline;
211 }
212 
213 int
214 softnic_pipeline_port_in_create(struct pmd_internals *softnic,
215 	const char *pipeline_name,
216 	struct softnic_port_in_params *params,
217 	int enabled)
218 {
219 	struct rte_pipeline_port_in_params p;
220 
221 	union {
222 		struct rte_port_ethdev_reader_params ethdev;
223 		struct rte_port_ring_reader_params ring;
224 		struct rte_port_sched_reader_params sched;
225 		struct rte_port_fd_reader_params fd;
226 		struct rte_port_source_params source;
227 	} pp;
228 
229 	struct pipeline *pipeline;
230 	struct softnic_port_in *port_in;
231 	struct softnic_port_in_action_profile *ap;
232 	struct rte_port_in_action *action;
233 	uint32_t port_id;
234 	int status;
235 
236 	memset(&p, 0, sizeof(p));
237 	memset(&pp, 0, sizeof(pp));
238 
239 	/* Check input params */
240 	if (pipeline_name == NULL ||
241 		params == NULL ||
242 		params->burst_size == 0 ||
243 		params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
244 		return -1;
245 
246 	pipeline = softnic_pipeline_find(softnic, pipeline_name);
247 	if (pipeline == NULL)
248 		return -1;
249 
250 	ap = NULL;
251 	if (strlen(params->action_profile_name)) {
252 		ap = softnic_port_in_action_profile_find(softnic,
253 			params->action_profile_name);
254 		if (ap == NULL)
255 			return -1;
256 	}
257 
258 	switch (params->type) {
259 	case PORT_IN_RXQ:
260 	{
261 		struct softnic_link *link;
262 
263 		link = softnic_link_find(softnic, params->dev_name);
264 		if (link == NULL)
265 			return -1;
266 
267 		if (params->rxq.queue_id >= link->n_rxq)
268 			return -1;
269 
270 		pp.ethdev.port_id = link->port_id;
271 		pp.ethdev.queue_id = params->rxq.queue_id;
272 
273 		p.ops = &rte_port_ethdev_reader_ops;
274 		p.arg_create = &pp.ethdev;
275 		break;
276 	}
277 
278 	case PORT_IN_SWQ:
279 	{
280 		struct softnic_swq *swq;
281 
282 		swq = softnic_swq_find(softnic, params->dev_name);
283 		if (swq == NULL)
284 			return -1;
285 
286 		pp.ring.ring = swq->r;
287 
288 		p.ops = &rte_port_ring_reader_ops;
289 		p.arg_create = &pp.ring;
290 		break;
291 	}
292 
293 	case PORT_IN_TMGR:
294 	{
295 		struct softnic_tmgr_port *tmgr_port;
296 
297 		tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
298 		if (tmgr_port == NULL)
299 			return -1;
300 
301 		pp.sched.sched = tmgr_port->s;
302 
303 		p.ops = &rte_port_sched_reader_ops;
304 		p.arg_create = &pp.sched;
305 		break;
306 	}
307 
308 	case PORT_IN_TAP:
309 	{
310 		struct softnic_tap *tap;
311 		struct softnic_mempool *mempool;
312 
313 		tap = softnic_tap_find(softnic, params->dev_name);
314 		mempool = softnic_mempool_find(softnic, params->tap.mempool_name);
315 		if (tap == NULL || mempool == NULL)
316 			return -1;
317 
318 		pp.fd.fd = tap->fd;
319 		pp.fd.mempool = mempool->m;
320 		pp.fd.mtu = params->tap.mtu;
321 
322 		p.ops = &rte_port_fd_reader_ops;
323 		p.arg_create = &pp.fd;
324 		break;
325 	}
326 
327 	case PORT_IN_SOURCE:
328 	{
329 		struct softnic_mempool *mempool;
330 
331 		mempool = softnic_mempool_find(softnic, params->source.mempool_name);
332 		if (mempool == NULL)
333 			return -1;
334 
335 		pp.source.mempool = mempool->m;
336 		pp.source.file_name = params->source.file_name;
337 		pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
338 
339 		p.ops = &rte_port_source_ops;
340 		p.arg_create = &pp.source;
341 		break;
342 	}
343 
344 	default:
345 		return -1;
346 	}
347 
348 	p.burst_size = params->burst_size;
349 
350 	/* Resource create */
351 	action = NULL;
352 	p.f_action = NULL;
353 	p.arg_ah = NULL;
354 
355 	if (ap) {
356 		action = rte_port_in_action_create(ap->ap,
357 			softnic->params.cpu_id);
358 		if (action == NULL)
359 			return -1;
360 
361 		status = rte_port_in_action_params_get(action,
362 			&p);
363 		if (status) {
364 			rte_port_in_action_free(action);
365 			return -1;
366 		}
367 	}
368 
369 	status = rte_pipeline_port_in_create(pipeline->p,
370 		&p,
371 		&port_id);
372 	if (status) {
373 		rte_port_in_action_free(action);
374 		return -1;
375 	}
376 
377 	if (enabled)
378 		rte_pipeline_port_in_enable(pipeline->p, port_id);
379 
380 	/* Pipeline */
381 	port_in = &pipeline->port_in[pipeline->n_ports_in];
382 	memcpy(&port_in->params, params, sizeof(*params));
383 	port_in->ap = ap;
384 	port_in->a = action;
385 	pipeline->n_ports_in++;
386 
387 	return 0;
388 }
389 
390 int
391 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
392 	const char *pipeline_name,
393 	uint32_t port_id,
394 	uint32_t table_id)
395 {
396 	struct pipeline *pipeline;
397 	int status;
398 
399 	/* Check input params */
400 	if (pipeline_name == NULL)
401 		return -1;
402 
403 	pipeline = softnic_pipeline_find(softnic, pipeline_name);
404 	if (pipeline == NULL ||
405 		port_id >= pipeline->n_ports_in ||
406 		table_id >= pipeline->n_tables)
407 		return -1;
408 
409 	/* Resource */
410 	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
411 		port_id,
412 		table_id);
413 
414 	return status;
415 }
416 
417 int
418 softnic_pipeline_port_out_create(struct pmd_internals *softnic,
419 	const char *pipeline_name,
420 	struct softnic_port_out_params *params)
421 {
422 	struct rte_pipeline_port_out_params p;
423 
424 	union {
425 		struct rte_port_ethdev_writer_params ethdev;
426 		struct rte_port_ring_writer_params ring;
427 		struct rte_port_sched_writer_params sched;
428 		struct rte_port_fd_writer_params fd;
429 		struct rte_port_sink_params sink;
430 	} pp;
431 
432 	union {
433 		struct rte_port_ethdev_writer_nodrop_params ethdev;
434 		struct rte_port_ring_writer_nodrop_params ring;
435 		struct rte_port_fd_writer_nodrop_params fd;
436 	} pp_nodrop;
437 
438 	struct pipeline *pipeline;
439 	struct softnic_port_out *port_out;
440 	uint32_t port_id;
441 	int status;
442 
443 	memset(&p, 0, sizeof(p));
444 	memset(&pp, 0, sizeof(pp));
445 	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
446 
447 	/* Check input params */
448 	if (pipeline_name == NULL ||
449 		params == NULL ||
450 		params->burst_size == 0 ||
451 		params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)
452 		return -1;
453 
454 	pipeline = softnic_pipeline_find(softnic, pipeline_name);
455 	if (pipeline == NULL)
456 		return -1;
457 
458 	switch (params->type) {
459 	case PORT_OUT_TXQ:
460 	{
461 		struct softnic_link *link;
462 
463 		link = softnic_link_find(softnic, params->dev_name);
464 		if (link == NULL)
465 			return -1;
466 
467 		if (params->txq.queue_id >= link->n_txq)
468 			return -1;
469 
470 		pp.ethdev.port_id = link->port_id;
471 		pp.ethdev.queue_id = params->txq.queue_id;
472 		pp.ethdev.tx_burst_sz = params->burst_size;
473 
474 		pp_nodrop.ethdev.port_id = link->port_id;
475 		pp_nodrop.ethdev.queue_id = params->txq.queue_id;
476 		pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
477 		pp_nodrop.ethdev.n_retries = params->n_retries;
478 
479 		if (params->retry == 0) {
480 			p.ops = &rte_port_ethdev_writer_ops;
481 			p.arg_create = &pp.ethdev;
482 		} else {
483 			p.ops = &rte_port_ethdev_writer_nodrop_ops;
484 			p.arg_create = &pp_nodrop.ethdev;
485 		}
486 		break;
487 	}
488 
489 	case PORT_OUT_SWQ:
490 	{
491 		struct softnic_swq *swq;
492 
493 		swq = softnic_swq_find(softnic, params->dev_name);
494 		if (swq == NULL)
495 			return -1;
496 
497 		pp.ring.ring = swq->r;
498 		pp.ring.tx_burst_sz = params->burst_size;
499 
500 		pp_nodrop.ring.ring = swq->r;
501 		pp_nodrop.ring.tx_burst_sz = params->burst_size;
502 		pp_nodrop.ring.n_retries = params->n_retries;
503 
504 		if (params->retry == 0) {
505 			p.ops = &rte_port_ring_writer_ops;
506 			p.arg_create = &pp.ring;
507 		} else {
508 			p.ops = &rte_port_ring_writer_nodrop_ops;
509 			p.arg_create = &pp_nodrop.ring;
510 		}
511 		break;
512 	}
513 
514 	case PORT_OUT_TMGR:
515 	{
516 		struct softnic_tmgr_port *tmgr_port;
517 
518 		tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name);
519 		if (tmgr_port == NULL)
520 			return -1;
521 
522 		pp.sched.sched = tmgr_port->s;
523 		pp.sched.tx_burst_sz = params->burst_size;
524 
525 		p.ops = &rte_port_sched_writer_ops;
526 		p.arg_create = &pp.sched;
527 		break;
528 	}
529 
530 	case PORT_OUT_TAP:
531 	{
532 		struct softnic_tap *tap;
533 
534 		tap = softnic_tap_find(softnic, params->dev_name);
535 		if (tap == NULL)
536 			return -1;
537 
538 		pp.fd.fd = tap->fd;
539 		pp.fd.tx_burst_sz = params->burst_size;
540 
541 		pp_nodrop.fd.fd = tap->fd;
542 		pp_nodrop.fd.tx_burst_sz = params->burst_size;
543 		pp_nodrop.fd.n_retries = params->n_retries;
544 
545 		if (params->retry == 0) {
546 			p.ops = &rte_port_fd_writer_ops;
547 			p.arg_create = &pp.fd;
548 		} else {
549 			p.ops = &rte_port_fd_writer_nodrop_ops;
550 			p.arg_create = &pp_nodrop.fd;
551 		}
552 		break;
553 	}
554 
555 	case PORT_OUT_SINK:
556 	{
557 		pp.sink.file_name = params->sink.file_name;
558 		pp.sink.max_n_pkts = params->sink.max_n_pkts;
559 
560 		p.ops = &rte_port_sink_ops;
561 		p.arg_create = &pp.sink;
562 		break;
563 	}
564 
565 	default:
566 		return -1;
567 	}
568 
569 	p.f_action = NULL;
570 	p.arg_ah = NULL;
571 
572 	/* Resource create */
573 	status = rte_pipeline_port_out_create(pipeline->p,
574 		&p,
575 		&port_id);
576 
577 	if (status)
578 		return -1;
579 
580 	/* Pipeline */
581 	port_out = &pipeline->port_out[pipeline->n_ports_out];
582 	memcpy(&port_out->params, params, sizeof(*params));
583 	pipeline->n_ports_out++;
584 
585 	return 0;
586 }
587 
588 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
589 	/* Protocol */
590 	[0] = {
591 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
592 		.size = sizeof(uint8_t),
593 		.field_index = 0,
594 		.input_index = 0,
595 		.offset = offsetof(struct ipv4_hdr, next_proto_id),
596 	},
597 
598 	/* Source IP address (IPv4) */
599 	[1] = {
600 		.type = RTE_ACL_FIELD_TYPE_MASK,
601 		.size = sizeof(uint32_t),
602 		.field_index = 1,
603 		.input_index = 1,
604 		.offset = offsetof(struct ipv4_hdr, src_addr),
605 	},
606 
607 	/* Destination IP address (IPv4) */
608 	[2] = {
609 		.type = RTE_ACL_FIELD_TYPE_MASK,
610 		.size = sizeof(uint32_t),
611 		.field_index = 2,
612 		.input_index = 2,
613 		.offset = offsetof(struct ipv4_hdr, dst_addr),
614 	},
615 
616 	/* Source Port */
617 	[3] = {
618 		.type = RTE_ACL_FIELD_TYPE_RANGE,
619 		.size = sizeof(uint16_t),
620 		.field_index = 3,
621 		.input_index = 3,
622 		.offset = sizeof(struct ipv4_hdr) +
623 			offsetof(struct tcp_hdr, src_port),
624 	},
625 
626 	/* Destination Port */
627 	[4] = {
628 		.type = RTE_ACL_FIELD_TYPE_RANGE,
629 		.size = sizeof(uint16_t),
630 		.field_index = 4,
631 		.input_index = 3,
632 		.offset = sizeof(struct ipv4_hdr) +
633 			offsetof(struct tcp_hdr, dst_port),
634 	},
635 };
636 
637 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
638 	/* Protocol */
639 	[0] = {
640 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
641 		.size = sizeof(uint8_t),
642 		.field_index = 0,
643 		.input_index = 0,
644 		.offset = offsetof(struct ipv6_hdr, proto),
645 	},
646 
647 	/* Source IP address (IPv6) */
648 	[1] = {
649 		.type = RTE_ACL_FIELD_TYPE_MASK,
650 		.size = sizeof(uint32_t),
651 		.field_index = 1,
652 		.input_index = 1,
653 		.offset = offsetof(struct ipv6_hdr, src_addr[0]),
654 	},
655 
656 	[2] = {
657 		.type = RTE_ACL_FIELD_TYPE_MASK,
658 		.size = sizeof(uint32_t),
659 		.field_index = 2,
660 		.input_index = 2,
661 		.offset = offsetof(struct ipv6_hdr, src_addr[4]),
662 	},
663 
664 	[3] = {
665 		.type = RTE_ACL_FIELD_TYPE_MASK,
666 		.size = sizeof(uint32_t),
667 		.field_index = 3,
668 		.input_index = 3,
669 		.offset = offsetof(struct ipv6_hdr, src_addr[8]),
670 	},
671 
672 	[4] = {
673 		.type = RTE_ACL_FIELD_TYPE_MASK,
674 		.size = sizeof(uint32_t),
675 		.field_index = 4,
676 		.input_index = 4,
677 		.offset = offsetof(struct ipv6_hdr, src_addr[12]),
678 	},
679 
680 	/* Destination IP address (IPv6) */
681 	[5] = {
682 		.type = RTE_ACL_FIELD_TYPE_MASK,
683 		.size = sizeof(uint32_t),
684 		.field_index = 5,
685 		.input_index = 5,
686 		.offset = offsetof(struct ipv6_hdr, dst_addr[0]),
687 	},
688 
689 	[6] = {
690 		.type = RTE_ACL_FIELD_TYPE_MASK,
691 		.size = sizeof(uint32_t),
692 		.field_index = 6,
693 		.input_index = 6,
694 		.offset = offsetof(struct ipv6_hdr, dst_addr[4]),
695 	},
696 
697 	[7] = {
698 		.type = RTE_ACL_FIELD_TYPE_MASK,
699 		.size = sizeof(uint32_t),
700 		.field_index = 7,
701 		.input_index = 7,
702 		.offset = offsetof(struct ipv6_hdr, dst_addr[8]),
703 	},
704 
705 	[8] = {
706 		.type = RTE_ACL_FIELD_TYPE_MASK,
707 		.size = sizeof(uint32_t),
708 		.field_index = 8,
709 		.input_index = 8,
710 		.offset = offsetof(struct ipv6_hdr, dst_addr[12]),
711 	},
712 
713 	/* Source Port */
714 	[9] = {
715 		.type = RTE_ACL_FIELD_TYPE_RANGE,
716 		.size = sizeof(uint16_t),
717 		.field_index = 9,
718 		.input_index = 9,
719 		.offset = sizeof(struct ipv6_hdr) +
720 			offsetof(struct tcp_hdr, src_port),
721 	},
722 
723 	/* Destination Port */
724 	[10] = {
725 		.type = RTE_ACL_FIELD_TYPE_RANGE,
726 		.size = sizeof(uint16_t),
727 		.field_index = 10,
728 		.input_index = 9,
729 		.offset = sizeof(struct ipv6_hdr) +
730 			offsetof(struct tcp_hdr, dst_port),
731 	},
732 };
733 
734 int
735 softnic_pipeline_table_create(struct pmd_internals *softnic,
736 	const char *pipeline_name,
737 	struct softnic_table_params *params)
738 {
739 	char name[NAME_MAX];
740 	struct rte_pipeline_table_params p;
741 
742 	union {
743 		struct rte_table_acl_params acl;
744 		struct rte_table_array_params array;
745 		struct rte_table_hash_params hash;
746 		struct rte_table_lpm_params lpm;
747 		struct rte_table_lpm_ipv6_params lpm_ipv6;
748 	} pp;
749 
750 	struct pipeline *pipeline;
751 	struct softnic_table *table;
752 	struct softnic_table_action_profile *ap;
753 	struct rte_table_action *action;
754 	uint32_t table_id;
755 	int status;
756 
757 	memset(&p, 0, sizeof(p));
758 	memset(&pp, 0, sizeof(pp));
759 
760 	/* Check input params */
761 	if (pipeline_name == NULL ||
762 		params == NULL)
763 		return -1;
764 
765 	pipeline = softnic_pipeline_find(softnic, pipeline_name);
766 	if (pipeline == NULL ||
767 		pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
768 		return -1;
769 
770 	ap = NULL;
771 	if (strlen(params->action_profile_name)) {
772 		ap = softnic_table_action_profile_find(softnic,
773 			params->action_profile_name);
774 		if (ap == NULL)
775 			return -1;
776 	}
777 
778 	snprintf(name, NAME_MAX, "%s_%s_table%u",
779 		softnic->params.name, pipeline_name, pipeline->n_tables);
780 
781 	switch (params->match_type) {
782 	case TABLE_ACL:
783 	{
784 		uint32_t ip_header_offset = params->match.acl.ip_header_offset -
785 			(sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
786 		uint32_t i;
787 
788 		if (params->match.acl.n_rules == 0)
789 			return -1;
790 
791 		pp.acl.name = name;
792 		pp.acl.n_rules = params->match.acl.n_rules;
793 		if (params->match.acl.ip_version) {
794 			memcpy(&pp.acl.field_format,
795 				&table_acl_field_format_ipv4,
796 				sizeof(table_acl_field_format_ipv4));
797 			pp.acl.n_rule_fields =
798 				RTE_DIM(table_acl_field_format_ipv4);
799 		} else {
800 			memcpy(&pp.acl.field_format,
801 				&table_acl_field_format_ipv6,
802 				sizeof(table_acl_field_format_ipv6));
803 			pp.acl.n_rule_fields =
804 				RTE_DIM(table_acl_field_format_ipv6);
805 		}
806 
807 		for (i = 0; i < pp.acl.n_rule_fields; i++)
808 			pp.acl.field_format[i].offset += ip_header_offset;
809 
810 		p.ops = &rte_table_acl_ops;
811 		p.arg_create = &pp.acl;
812 		break;
813 	}
814 
815 	case TABLE_ARRAY:
816 	{
817 		if (params->match.array.n_keys == 0)
818 			return -1;
819 
820 		pp.array.n_entries = params->match.array.n_keys;
821 		pp.array.offset = params->match.array.key_offset;
822 
823 		p.ops = &rte_table_array_ops;
824 		p.arg_create = &pp.array;
825 		break;
826 	}
827 
828 	case TABLE_HASH:
829 	{
830 		struct rte_table_ops *ops;
831 		rte_table_hash_op_hash f_hash;
832 
833 		if (params->match.hash.n_keys == 0)
834 			return -1;
835 
836 		switch (params->match.hash.key_size) {
837 		case  8:
838 			f_hash = rte_table_hash_crc_key8;
839 			break;
840 		case 16:
841 			f_hash = rte_table_hash_crc_key16;
842 			break;
843 		case 24:
844 			f_hash = rte_table_hash_crc_key24;
845 			break;
846 		case 32:
847 			f_hash = rte_table_hash_crc_key32;
848 			break;
849 		case 40:
850 			f_hash = rte_table_hash_crc_key40;
851 			break;
852 		case 48:
853 			f_hash = rte_table_hash_crc_key48;
854 			break;
855 		case 56:
856 			f_hash = rte_table_hash_crc_key56;
857 			break;
858 		case 64:
859 			f_hash = rte_table_hash_crc_key64;
860 			break;
861 		default:
862 			return -1;
863 		}
864 
865 		pp.hash.name = name;
866 		pp.hash.key_size = params->match.hash.key_size;
867 		pp.hash.key_offset = params->match.hash.key_offset;
868 		pp.hash.key_mask = params->match.hash.key_mask;
869 		pp.hash.n_keys = params->match.hash.n_keys;
870 		pp.hash.n_buckets = params->match.hash.n_buckets;
871 		pp.hash.f_hash = f_hash;
872 		pp.hash.seed = 0;
873 
874 		if (params->match.hash.extendable_bucket)
875 			switch (params->match.hash.key_size) {
876 			case  8:
877 				ops = &rte_table_hash_key8_ext_ops;
878 				break;
879 			case 16:
880 				ops = &rte_table_hash_key16_ext_ops;
881 				break;
882 			default:
883 				ops = &rte_table_hash_ext_ops;
884 			}
885 		else
886 			switch (params->match.hash.key_size) {
887 			case  8:
888 				ops = &rte_table_hash_key8_lru_ops;
889 				break;
890 			case 16:
891 				ops = &rte_table_hash_key16_lru_ops;
892 				break;
893 			default:
894 				ops = &rte_table_hash_lru_ops;
895 			}
896 
897 		p.ops = ops;
898 		p.arg_create = &pp.hash;
899 		break;
900 	}
901 
902 	case TABLE_LPM:
903 	{
904 		if (params->match.lpm.n_rules == 0)
905 			return -1;
906 
907 		switch (params->match.lpm.key_size) {
908 		case 4:
909 		{
910 			pp.lpm.name = name;
911 			pp.lpm.n_rules = params->match.lpm.n_rules;
912 			pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
913 			pp.lpm.flags = 0;
914 			pp.lpm.entry_unique_size = p.action_data_size +
915 				sizeof(struct rte_pipeline_table_entry);
916 			pp.lpm.offset = params->match.lpm.key_offset;
917 
918 			p.ops = &rte_table_lpm_ops;
919 			p.arg_create = &pp.lpm;
920 			break;
921 		}
922 
923 		case 16:
924 		{
925 			pp.lpm_ipv6.name = name;
926 			pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
927 			pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
928 			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
929 				sizeof(struct rte_pipeline_table_entry);
930 			pp.lpm_ipv6.offset = params->match.lpm.key_offset;
931 
932 			p.ops = &rte_table_lpm_ipv6_ops;
933 			p.arg_create = &pp.lpm_ipv6;
934 			break;
935 		}
936 
937 		default:
938 			return -1;
939 		}
940 
941 		break;
942 	}
943 
944 	case TABLE_STUB:
945 	{
946 		p.ops = &rte_table_stub_ops;
947 		p.arg_create = NULL;
948 		break;
949 	}
950 
951 	default:
952 		return -1;
953 	}
954 
955 	/* Resource create */
956 	action = NULL;
957 	p.f_action_hit = NULL;
958 	p.f_action_miss = NULL;
959 	p.arg_ah = NULL;
960 
961 	if (ap) {
962 		action = rte_table_action_create(ap->ap,
963 			softnic->params.cpu_id);
964 		if (action == NULL)
965 			return -1;
966 
967 		status = rte_table_action_table_params_get(action,
968 			&p);
969 		if (status ||
970 			((p.action_data_size +
971 			sizeof(struct rte_pipeline_table_entry)) >
972 			TABLE_RULE_ACTION_SIZE_MAX)) {
973 			rte_table_action_free(action);
974 			return -1;
975 		}
976 	}
977 
978 	if (params->match_type == TABLE_LPM) {
979 		if (params->match.lpm.key_size == 4)
980 			pp.lpm.entry_unique_size = p.action_data_size +
981 				sizeof(struct rte_pipeline_table_entry);
982 
983 		if (params->match.lpm.key_size == 16)
984 			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
985 				sizeof(struct rte_pipeline_table_entry);
986 	}
987 
988 	status = rte_pipeline_table_create(pipeline->p,
989 		&p,
990 		&table_id);
991 	if (status) {
992 		rte_table_action_free(action);
993 		return -1;
994 	}
995 
996 	/* Pipeline */
997 	table = &pipeline->table[pipeline->n_tables];
998 	memcpy(&table->params, params, sizeof(*params));
999 	table->ap = ap;
1000 	table->a = action;
1001 	TAILQ_INIT(&table->flows);
1002 	TAILQ_INIT(&table->meter_profiles);
1003 	memset(&table->dscp_table, 0, sizeof(table->dscp_table));
1004 	pipeline->n_tables++;
1005 
1006 	return 0;
1007 }
1008 
1009 int
1010 softnic_pipeline_port_out_find(struct pmd_internals *softnic,
1011 		const char *pipeline_name,
1012 		const char *name,
1013 		uint32_t *port_id)
1014 {
1015 	struct pipeline *pipeline;
1016 	uint32_t i;
1017 
1018 	if (softnic == NULL ||
1019 			pipeline_name == NULL ||
1020 			name == NULL ||
1021 			port_id == NULL)
1022 		return -1;
1023 
1024 	pipeline = softnic_pipeline_find(softnic, pipeline_name);
1025 	if (pipeline == NULL)
1026 		return -1;
1027 
1028 	for (i = 0; i < pipeline->n_ports_out; i++)
1029 		if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) {
1030 			*port_id = i;
1031 			return 0;
1032 		}
1033 
1034 	return -1;
1035 }
1036 
1037 struct softnic_table_meter_profile *
1038 softnic_pipeline_table_meter_profile_find(struct softnic_table *table,
1039 	uint32_t meter_profile_id)
1040 {
1041 	struct softnic_table_meter_profile *mp;
1042 
1043 	TAILQ_FOREACH(mp, &table->meter_profiles, node)
1044 		if (mp->meter_profile_id == meter_profile_id)
1045 			return mp;
1046 
1047 	return NULL;
1048 }
1049