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