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