1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2016 Intel Corporation
7 #include <rte_common.h>
8 #include <rte_malloc.h>
12 #include <rte_byteorder.h>
13 #include <rte_table_acl.h>
15 #include "pipeline_firewall_be.h"
18 struct pipeline_firewall {
20 pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
23 uint32_t n_rule_fields;
24 struct rte_acl_field_def *field_format;
25 uint32_t field_format_size;
26 } __rte_cache_aligned;
29 pipeline_firewall_msg_req_custom_handler(struct pipeline *p, void *msg);
31 static pipeline_msg_req_handler handlers[] = {
32 [PIPELINE_MSG_REQ_PING] =
33 pipeline_msg_req_ping_handler,
34 [PIPELINE_MSG_REQ_STATS_PORT_IN] =
35 pipeline_msg_req_stats_port_in_handler,
36 [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
37 pipeline_msg_req_stats_port_out_handler,
38 [PIPELINE_MSG_REQ_STATS_TABLE] =
39 pipeline_msg_req_stats_table_handler,
40 [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
41 pipeline_msg_req_port_in_enable_handler,
42 [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
43 pipeline_msg_req_port_in_disable_handler,
44 [PIPELINE_MSG_REQ_CUSTOM] =
45 pipeline_firewall_msg_req_custom_handler,
49 pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg);
52 pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg);
55 pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg);
58 pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg);
61 pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg);
64 pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg);
66 static pipeline_msg_req_handler custom_handlers[] = {
67 [PIPELINE_FIREWALL_MSG_REQ_ADD] =
68 pipeline_firewall_msg_req_add_handler,
69 [PIPELINE_FIREWALL_MSG_REQ_DEL] =
70 pipeline_firewall_msg_req_del_handler,
71 [PIPELINE_FIREWALL_MSG_REQ_ADD_BULK] =
72 pipeline_firewall_msg_req_add_bulk_handler,
73 [PIPELINE_FIREWALL_MSG_REQ_DEL_BULK] =
74 pipeline_firewall_msg_req_del_bulk_handler,
75 [PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT] =
76 pipeline_firewall_msg_req_add_default_handler,
77 [PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT] =
78 pipeline_firewall_msg_req_del_default_handler,
84 struct firewall_table_entry {
85 struct rte_pipeline_table_entry head;
88 static struct rte_acl_field_def field_format_ipv4[] = {
91 .type = RTE_ACL_FIELD_TYPE_BITMASK,
92 .size = sizeof(uint8_t),
95 .offset = sizeof(struct ether_hdr) +
96 offsetof(struct ipv4_hdr, next_proto_id),
99 /* Source IP address (IPv4) */
101 .type = RTE_ACL_FIELD_TYPE_MASK,
102 .size = sizeof(uint32_t),
105 .offset = sizeof(struct ether_hdr) +
106 offsetof(struct ipv4_hdr, src_addr),
109 /* Destination IP address (IPv4) */
111 .type = RTE_ACL_FIELD_TYPE_MASK,
112 .size = sizeof(uint32_t),
115 .offset = sizeof(struct ether_hdr) +
116 offsetof(struct ipv4_hdr, dst_addr),
121 .type = RTE_ACL_FIELD_TYPE_RANGE,
122 .size = sizeof(uint16_t),
125 .offset = sizeof(struct ether_hdr) +
126 sizeof(struct ipv4_hdr) +
127 offsetof(struct tcp_hdr, src_port),
130 /* Destination Port */
132 .type = RTE_ACL_FIELD_TYPE_RANGE,
133 .size = sizeof(uint16_t),
136 .offset = sizeof(struct ether_hdr) +
137 sizeof(struct ipv4_hdr) +
138 offsetof(struct tcp_hdr, dst_port),
142 #define SIZEOF_VLAN_HDR 4
144 static struct rte_acl_field_def field_format_vlan_ipv4[] = {
147 .type = RTE_ACL_FIELD_TYPE_BITMASK,
148 .size = sizeof(uint8_t),
151 .offset = sizeof(struct ether_hdr) +
153 offsetof(struct ipv4_hdr, next_proto_id),
156 /* Source IP address (IPv4) */
158 .type = RTE_ACL_FIELD_TYPE_MASK,
159 .size = sizeof(uint32_t),
162 .offset = sizeof(struct ether_hdr) +
164 offsetof(struct ipv4_hdr, src_addr),
167 /* Destination IP address (IPv4) */
169 .type = RTE_ACL_FIELD_TYPE_MASK,
170 .size = sizeof(uint32_t),
173 .offset = sizeof(struct ether_hdr) +
175 offsetof(struct ipv4_hdr, dst_addr),
180 .type = RTE_ACL_FIELD_TYPE_RANGE,
181 .size = sizeof(uint16_t),
184 .offset = sizeof(struct ether_hdr) +
186 sizeof(struct ipv4_hdr) +
187 offsetof(struct tcp_hdr, src_port),
190 /* Destination Port */
192 .type = RTE_ACL_FIELD_TYPE_RANGE,
193 .size = sizeof(uint16_t),
196 .offset = sizeof(struct ether_hdr) +
198 sizeof(struct ipv4_hdr) +
199 offsetof(struct tcp_hdr, dst_port),
203 #define SIZEOF_QINQ_HEADER 8
205 static struct rte_acl_field_def field_format_qinq_ipv4[] = {
208 .type = RTE_ACL_FIELD_TYPE_BITMASK,
209 .size = sizeof(uint8_t),
212 .offset = sizeof(struct ether_hdr) +
214 offsetof(struct ipv4_hdr, next_proto_id),
217 /* Source IP address (IPv4) */
219 .type = RTE_ACL_FIELD_TYPE_MASK,
220 .size = sizeof(uint32_t),
223 .offset = sizeof(struct ether_hdr) +
225 offsetof(struct ipv4_hdr, src_addr),
228 /* Destination IP address (IPv4) */
230 .type = RTE_ACL_FIELD_TYPE_MASK,
231 .size = sizeof(uint32_t),
234 .offset = sizeof(struct ether_hdr) +
236 offsetof(struct ipv4_hdr, dst_addr),
241 .type = RTE_ACL_FIELD_TYPE_RANGE,
242 .size = sizeof(uint16_t),
245 .offset = sizeof(struct ether_hdr) +
247 sizeof(struct ipv4_hdr) +
248 offsetof(struct tcp_hdr, src_port),
251 /* Destination Port */
253 .type = RTE_ACL_FIELD_TYPE_RANGE,
254 .size = sizeof(uint16_t),
257 .offset = sizeof(struct ether_hdr) +
259 sizeof(struct ipv4_hdr) +
260 offsetof(struct tcp_hdr, dst_port),
265 pipeline_firewall_parse_args(struct pipeline_firewall *p,
266 struct pipeline_params *params)
268 uint32_t n_rules_present = 0;
269 uint32_t pkt_type_present = 0;
273 p->n_rules = 4 * 1024;
274 p->n_rule_fields = RTE_DIM(field_format_ipv4);
275 p->field_format = field_format_ipv4;
276 p->field_format_size = sizeof(field_format_ipv4);
278 for (i = 0; i < params->n_args; i++) {
279 char *arg_name = params->args_name[i];
280 char *arg_value = params->args_value[i];
282 if (strcmp(arg_name, "n_rules") == 0) {
285 PIPELINE_PARSE_ERR_DUPLICATE(
286 n_rules_present == 0, params->name,
290 status = parser_read_uint32(&p->n_rules,
292 PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
293 params->name, arg_name, arg_value);
294 PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
295 params->name, arg_name, arg_value);
299 if (strcmp(arg_name, "pkt_type") == 0) {
300 PIPELINE_PARSE_ERR_DUPLICATE(
301 pkt_type_present == 0, params->name,
303 pkt_type_present = 1;
306 if (strcmp(arg_value, "ipv4") == 0) {
307 p->n_rule_fields = RTE_DIM(field_format_ipv4);
308 p->field_format = field_format_ipv4;
309 p->field_format_size =
310 sizeof(field_format_ipv4);
315 if (strcmp(arg_value, "vlan_ipv4") == 0) {
317 RTE_DIM(field_format_vlan_ipv4);
318 p->field_format = field_format_vlan_ipv4;
319 p->field_format_size =
320 sizeof(field_format_vlan_ipv4);
325 if (strcmp(arg_value, "qinq_ipv4") == 0) {
327 RTE_DIM(field_format_qinq_ipv4);
328 p->field_format = field_format_qinq_ipv4;
329 p->field_format_size =
330 sizeof(field_format_qinq_ipv4);
335 PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
336 arg_name, arg_value);
340 PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
347 pipeline_firewall_init(struct pipeline_params *params,
348 __rte_unused void *arg)
351 struct pipeline_firewall *p_fw;
354 /* Check input arguments */
355 if ((params == NULL) ||
356 (params->n_ports_in == 0) ||
357 (params->n_ports_out == 0))
360 /* Memory allocation */
361 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_firewall));
362 p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
363 p_fw = (struct pipeline_firewall *) p;
367 strcpy(p->name, params->name);
368 p->log_level = params->log_level;
370 PLOG(p, HIGH, "Firewall");
372 /* Parse arguments */
373 if (pipeline_firewall_parse_args(p_fw, params))
378 struct rte_pipeline_params pipeline_params = {
379 .name = params->name,
380 .socket_id = params->socket_id,
384 p->p = rte_pipeline_create(&pipeline_params);
392 p->n_ports_in = params->n_ports_in;
393 for (i = 0; i < p->n_ports_in; i++) {
394 struct rte_pipeline_port_in_params port_params = {
395 .ops = pipeline_port_in_params_get_ops(
396 ¶ms->port_in[i]),
397 .arg_create = pipeline_port_in_params_convert(
398 ¶ms->port_in[i]),
401 .burst_size = params->port_in[i].burst_size,
404 int status = rte_pipeline_port_in_create(p->p,
409 rte_pipeline_free(p->p);
416 p->n_ports_out = params->n_ports_out;
417 for (i = 0; i < p->n_ports_out; i++) {
418 struct rte_pipeline_port_out_params port_params = {
419 .ops = pipeline_port_out_params_get_ops(
420 ¶ms->port_out[i]),
421 .arg_create = pipeline_port_out_params_convert(
422 ¶ms->port_out[i]),
427 int status = rte_pipeline_port_out_create(p->p,
432 rte_pipeline_free(p->p);
441 struct rte_table_acl_params table_acl_params = {
442 .name = params->name,
443 .n_rules = p_fw->n_rules,
444 .n_rule_fields = p_fw->n_rule_fields,
447 struct rte_pipeline_table_params table_params = {
448 .ops = &rte_table_acl_ops,
449 .arg_create = &table_acl_params,
450 .f_action_hit = NULL,
451 .f_action_miss = NULL,
454 sizeof(struct firewall_table_entry) -
455 sizeof(struct rte_pipeline_table_entry),
460 memcpy(table_acl_params.field_format,
462 p_fw->field_format_size);
464 status = rte_pipeline_table_create(p->p,
469 rte_pipeline_free(p->p);
475 /* Connecting input ports to tables */
476 for (i = 0; i < p->n_ports_in; i++) {
477 int status = rte_pipeline_port_in_connect_to_table(p->p,
482 rte_pipeline_free(p->p);
488 /* Enable input ports */
489 for (i = 0; i < p->n_ports_in; i++) {
490 int status = rte_pipeline_port_in_enable(p->p,
494 rte_pipeline_free(p->p);
500 /* Check pipeline consistency */
501 if (rte_pipeline_check(p->p) < 0) {
502 rte_pipeline_free(p->p);
508 p->n_msgq = params->n_msgq;
509 for (i = 0; i < p->n_msgq; i++)
510 p->msgq_in[i] = params->msgq_in[i];
511 for (i = 0; i < p->n_msgq; i++)
512 p->msgq_out[i] = params->msgq_out[i];
514 /* Message handlers */
515 memcpy(p->handlers, handlers, sizeof(p->handlers));
516 memcpy(p_fw->custom_handlers,
518 sizeof(p_fw->custom_handlers));
524 pipeline_firewall_free(void *pipeline)
526 struct pipeline *p = (struct pipeline *) pipeline;
528 /* Check input arguments */
533 rte_pipeline_free(p->p);
539 pipeline_firewall_timer(void *pipeline)
541 struct pipeline *p = (struct pipeline *) pipeline;
543 pipeline_msg_req_handle(p);
544 rte_pipeline_flush(p->p);
550 pipeline_firewall_msg_req_custom_handler(struct pipeline *p,
553 struct pipeline_firewall *p_fw = (struct pipeline_firewall *) p;
554 struct pipeline_custom_msg_req *req = msg;
555 pipeline_msg_req_handler f_handle;
557 f_handle = (req->subtype < PIPELINE_FIREWALL_MSG_REQS) ?
558 p_fw->custom_handlers[req->subtype] :
559 pipeline_msg_req_invalid_handler;
561 if (f_handle == NULL)
562 f_handle = pipeline_msg_req_invalid_handler;
564 return f_handle(p, req);
568 pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg)
570 struct pipeline_firewall_add_msg_req *req = msg;
571 struct pipeline_firewall_add_msg_rsp *rsp = msg;
573 struct rte_table_acl_rule_add_params params;
574 struct firewall_table_entry entry = {
576 .action = RTE_PIPELINE_ACTION_PORT,
577 {.port_id = p->port_out_id[req->port_id]},
581 memset(¶ms, 0, sizeof(params));
583 switch (req->key.type) {
584 case PIPELINE_FIREWALL_IPV4_5TUPLE:
585 params.priority = req->priority;
586 params.field_value[0].value.u8 =
587 req->key.key.ipv4_5tuple.proto;
588 params.field_value[0].mask_range.u8 =
589 req->key.key.ipv4_5tuple.proto_mask;
590 params.field_value[1].value.u32 =
591 req->key.key.ipv4_5tuple.src_ip;
592 params.field_value[1].mask_range.u32 =
593 req->key.key.ipv4_5tuple.src_ip_mask;
594 params.field_value[2].value.u32 =
595 req->key.key.ipv4_5tuple.dst_ip;
596 params.field_value[2].mask_range.u32 =
597 req->key.key.ipv4_5tuple.dst_ip_mask;
598 params.field_value[3].value.u16 =
599 req->key.key.ipv4_5tuple.src_port_from;
600 params.field_value[3].mask_range.u16 =
601 req->key.key.ipv4_5tuple.src_port_to;
602 params.field_value[4].value.u16 =
603 req->key.key.ipv4_5tuple.dst_port_from;
604 params.field_value[4].mask_range.u16 =
605 req->key.key.ipv4_5tuple.dst_port_to;
609 rsp->status = -1; /* Error */
613 rsp->status = rte_pipeline_table_entry_add(p->p,
616 (struct rte_pipeline_table_entry *) &entry,
618 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
624 pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg)
626 struct pipeline_firewall_del_msg_req *req = msg;
627 struct pipeline_firewall_del_msg_rsp *rsp = msg;
629 struct rte_table_acl_rule_delete_params params;
631 memset(¶ms, 0, sizeof(params));
633 switch (req->key.type) {
634 case PIPELINE_FIREWALL_IPV4_5TUPLE:
635 params.field_value[0].value.u8 =
636 req->key.key.ipv4_5tuple.proto;
637 params.field_value[0].mask_range.u8 =
638 req->key.key.ipv4_5tuple.proto_mask;
639 params.field_value[1].value.u32 =
640 req->key.key.ipv4_5tuple.src_ip;
641 params.field_value[1].mask_range.u32 =
642 req->key.key.ipv4_5tuple.src_ip_mask;
643 params.field_value[2].value.u32 =
644 req->key.key.ipv4_5tuple.dst_ip;
645 params.field_value[2].mask_range.u32 =
646 req->key.key.ipv4_5tuple.dst_ip_mask;
647 params.field_value[3].value.u16 =
648 req->key.key.ipv4_5tuple.src_port_from;
649 params.field_value[3].mask_range.u16 =
650 req->key.key.ipv4_5tuple.src_port_to;
651 params.field_value[4].value.u16 =
652 req->key.key.ipv4_5tuple.dst_port_from;
653 params.field_value[4].mask_range.u16 =
654 req->key.key.ipv4_5tuple.dst_port_to;
658 rsp->status = -1; /* Error */
662 rsp->status = rte_pipeline_table_entry_delete(p->p,
672 pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
674 struct pipeline_firewall_add_bulk_msg_req *req = msg;
675 struct pipeline_firewall_add_bulk_msg_rsp *rsp = msg;
677 struct rte_table_acl_rule_add_params *params[req->n_keys];
678 struct firewall_table_entry *entries[req->n_keys];
682 n_keys = req->n_keys;
684 for (i = 0; i < n_keys; i++) {
685 entries[i] = rte_zmalloc(NULL,
686 sizeof(struct firewall_table_entry),
687 RTE_CACHE_LINE_SIZE);
688 if (entries[i] == NULL) {
693 params[i] = rte_zmalloc(NULL,
694 sizeof(struct rte_table_acl_rule_add_params),
695 RTE_CACHE_LINE_SIZE);
696 if (params[i] == NULL) {
701 entries[i]->head.action = RTE_PIPELINE_ACTION_PORT;
702 entries[i]->head.port_id = p->port_out_id[req->port_ids[i]];
704 switch (req->keys[i].type) {
705 case PIPELINE_FIREWALL_IPV4_5TUPLE:
706 params[i]->priority = req->priorities[i];
707 params[i]->field_value[0].value.u8 =
708 req->keys[i].key.ipv4_5tuple.proto;
709 params[i]->field_value[0].mask_range.u8 =
710 req->keys[i].key.ipv4_5tuple.proto_mask;
711 params[i]->field_value[1].value.u32 =
712 req->keys[i].key.ipv4_5tuple.src_ip;
713 params[i]->field_value[1].mask_range.u32 =
714 req->keys[i].key.ipv4_5tuple.src_ip_mask;
715 params[i]->field_value[2].value.u32 =
716 req->keys[i].key.ipv4_5tuple.dst_ip;
717 params[i]->field_value[2].mask_range.u32 =
718 req->keys[i].key.ipv4_5tuple.dst_ip_mask;
719 params[i]->field_value[3].value.u16 =
720 req->keys[i].key.ipv4_5tuple.src_port_from;
721 params[i]->field_value[3].mask_range.u16 =
722 req->keys[i].key.ipv4_5tuple.src_port_to;
723 params[i]->field_value[4].value.u16 =
724 req->keys[i].key.ipv4_5tuple.dst_port_from;
725 params[i]->field_value[4].mask_range.u16 =
726 req->keys[i].key.ipv4_5tuple.dst_port_to;
730 rsp->status = -1; /* Error */
732 for (i = 0; i < n_keys; i++) {
733 rte_free(entries[i]);
741 rsp->status = rte_pipeline_table_entry_add_bulk(p->p, p->table_id[0],
742 (void *)params, (struct rte_pipeline_table_entry **)entries,
743 n_keys, req->keys_found,
744 (struct rte_pipeline_table_entry **)req->entries_ptr);
746 for (i = 0; i < n_keys; i++) {
747 rte_free(entries[i]);
755 pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg)
757 struct pipeline_firewall_del_bulk_msg_req *req = msg;
758 struct pipeline_firewall_del_bulk_msg_rsp *rsp = msg;
760 struct rte_table_acl_rule_delete_params *params[req->n_keys];
764 n_keys = req->n_keys;
766 for (i = 0; i < n_keys; i++) {
767 params[i] = rte_zmalloc(NULL,
768 sizeof(struct rte_table_acl_rule_delete_params),
769 RTE_CACHE_LINE_SIZE);
770 if (params[i] == NULL) {
775 switch (req->keys[i].type) {
776 case PIPELINE_FIREWALL_IPV4_5TUPLE:
777 params[i]->field_value[0].value.u8 =
778 req->keys[i].key.ipv4_5tuple.proto;
779 params[i]->field_value[0].mask_range.u8 =
780 req->keys[i].key.ipv4_5tuple.proto_mask;
781 params[i]->field_value[1].value.u32 =
782 req->keys[i].key.ipv4_5tuple.src_ip;
783 params[i]->field_value[1].mask_range.u32 =
784 req->keys[i].key.ipv4_5tuple.src_ip_mask;
785 params[i]->field_value[2].value.u32 =
786 req->keys[i].key.ipv4_5tuple.dst_ip;
787 params[i]->field_value[2].mask_range.u32 =
788 req->keys[i].key.ipv4_5tuple.dst_ip_mask;
789 params[i]->field_value[3].value.u16 =
790 req->keys[i].key.ipv4_5tuple.src_port_from;
791 params[i]->field_value[3].mask_range.u16 =
792 req->keys[i].key.ipv4_5tuple.src_port_to;
793 params[i]->field_value[4].value.u16 =
794 req->keys[i].key.ipv4_5tuple.dst_port_from;
795 params[i]->field_value[4].mask_range.u16 =
796 req->keys[i].key.ipv4_5tuple.dst_port_to;
800 rsp->status = -1; /* Error */
802 for (i = 0; i < n_keys; i++)
809 rsp->status = rte_pipeline_table_entry_delete_bulk(p->p, p->table_id[0],
810 (void **)¶ms, n_keys, req->keys_found, NULL);
812 for (i = 0; i < n_keys; i++)
819 pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg)
821 struct pipeline_firewall_add_default_msg_req *req = msg;
822 struct pipeline_firewall_add_default_msg_rsp *rsp = msg;
824 struct firewall_table_entry default_entry = {
826 .action = RTE_PIPELINE_ACTION_PORT,
827 {.port_id = p->port_out_id[req->port_id]},
831 rsp->status = rte_pipeline_table_default_entry_add(p->p,
833 (struct rte_pipeline_table_entry *) &default_entry,
834 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
840 pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg)
842 struct pipeline_firewall_del_default_msg_rsp *rsp = msg;
844 rsp->status = rte_pipeline_table_default_entry_delete(p->p,
851 struct pipeline_be_ops pipeline_firewall_be_ops = {
852 .f_init = pipeline_firewall_init,
853 .f_free = pipeline_firewall_free,
855 .f_timer = pipeline_firewall_timer,