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