4 * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_ether.h>
41 #include <rte_byteorder.h>
42 #include <rte_table_acl.h>
44 #include "pipeline_firewall_be.h"
46 struct pipeline_firewall {
48 pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
51 uint32_t n_rule_fields;
52 struct rte_acl_field_def *field_format;
53 uint32_t field_format_size;
54 } __rte_cache_aligned;
57 pipeline_firewall_msg_req_custom_handler(struct pipeline *p, void *msg);
59 static pipeline_msg_req_handler handlers[] = {
60 [PIPELINE_MSG_REQ_PING] =
61 pipeline_msg_req_ping_handler,
62 [PIPELINE_MSG_REQ_STATS_PORT_IN] =
63 pipeline_msg_req_stats_port_in_handler,
64 [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
65 pipeline_msg_req_stats_port_out_handler,
66 [PIPELINE_MSG_REQ_STATS_TABLE] =
67 pipeline_msg_req_stats_table_handler,
68 [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
69 pipeline_msg_req_port_in_enable_handler,
70 [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
71 pipeline_msg_req_port_in_disable_handler,
72 [PIPELINE_MSG_REQ_CUSTOM] =
73 pipeline_firewall_msg_req_custom_handler,
77 pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg);
80 pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg);
83 pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg);
86 pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg);
88 static pipeline_msg_req_handler custom_handlers[] = {
89 [PIPELINE_FIREWALL_MSG_REQ_ADD] =
90 pipeline_firewall_msg_req_add_handler,
91 [PIPELINE_FIREWALL_MSG_REQ_DEL] =
92 pipeline_firewall_msg_req_del_handler,
93 [PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT] =
94 pipeline_firewall_msg_req_add_default_handler,
95 [PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT] =
96 pipeline_firewall_msg_req_del_default_handler,
102 struct firewall_table_entry {
103 struct rte_pipeline_table_entry head;
106 static struct rte_acl_field_def field_format_ipv4[] = {
109 .type = RTE_ACL_FIELD_TYPE_BITMASK,
110 .size = sizeof(uint8_t),
113 .offset = sizeof(struct ether_hdr) +
114 offsetof(struct ipv4_hdr, next_proto_id),
117 /* Source IP address (IPv4) */
119 .type = RTE_ACL_FIELD_TYPE_MASK,
120 .size = sizeof(uint32_t),
123 .offset = sizeof(struct ether_hdr) +
124 offsetof(struct ipv4_hdr, src_addr),
127 /* Destination IP address (IPv4) */
129 .type = RTE_ACL_FIELD_TYPE_MASK,
130 .size = sizeof(uint32_t),
133 .offset = sizeof(struct ether_hdr) +
134 offsetof(struct ipv4_hdr, dst_addr),
139 .type = RTE_ACL_FIELD_TYPE_RANGE,
140 .size = sizeof(uint16_t),
143 .offset = sizeof(struct ether_hdr) +
144 sizeof(struct ipv4_hdr) +
145 offsetof(struct tcp_hdr, src_port),
148 /* Destination Port */
150 .type = RTE_ACL_FIELD_TYPE_RANGE,
151 .size = sizeof(uint16_t),
154 .offset = sizeof(struct ether_hdr) +
155 sizeof(struct ipv4_hdr) +
156 offsetof(struct tcp_hdr, dst_port),
160 #define SIZEOF_VLAN_HDR 4
162 static struct rte_acl_field_def field_format_vlan_ipv4[] = {
165 .type = RTE_ACL_FIELD_TYPE_BITMASK,
166 .size = sizeof(uint8_t),
169 .offset = sizeof(struct ether_hdr) +
171 offsetof(struct ipv4_hdr, next_proto_id),
174 /* Source IP address (IPv4) */
176 .type = RTE_ACL_FIELD_TYPE_MASK,
177 .size = sizeof(uint32_t),
180 .offset = sizeof(struct ether_hdr) +
182 offsetof(struct ipv4_hdr, src_addr),
185 /* Destination IP address (IPv4) */
187 .type = RTE_ACL_FIELD_TYPE_MASK,
188 .size = sizeof(uint32_t),
191 .offset = sizeof(struct ether_hdr) +
193 offsetof(struct ipv4_hdr, dst_addr),
198 .type = RTE_ACL_FIELD_TYPE_RANGE,
199 .size = sizeof(uint16_t),
202 .offset = sizeof(struct ether_hdr) +
204 sizeof(struct ipv4_hdr) +
205 offsetof(struct tcp_hdr, src_port),
208 /* Destination Port */
210 .type = RTE_ACL_FIELD_TYPE_RANGE,
211 .size = sizeof(uint16_t),
214 .offset = sizeof(struct ether_hdr) +
216 sizeof(struct ipv4_hdr) +
217 offsetof(struct tcp_hdr, dst_port),
221 #define SIZEOF_QINQ_HEADER 8
223 static struct rte_acl_field_def field_format_qinq_ipv4[] = {
226 .type = RTE_ACL_FIELD_TYPE_BITMASK,
227 .size = sizeof(uint8_t),
230 .offset = sizeof(struct ether_hdr) +
232 offsetof(struct ipv4_hdr, next_proto_id),
235 /* Source IP address (IPv4) */
237 .type = RTE_ACL_FIELD_TYPE_MASK,
238 .size = sizeof(uint32_t),
241 .offset = sizeof(struct ether_hdr) +
243 offsetof(struct ipv4_hdr, src_addr),
246 /* Destination IP address (IPv4) */
248 .type = RTE_ACL_FIELD_TYPE_MASK,
249 .size = sizeof(uint32_t),
252 .offset = sizeof(struct ether_hdr) +
254 offsetof(struct ipv4_hdr, dst_addr),
259 .type = RTE_ACL_FIELD_TYPE_RANGE,
260 .size = sizeof(uint16_t),
263 .offset = sizeof(struct ether_hdr) +
265 sizeof(struct ipv4_hdr) +
266 offsetof(struct tcp_hdr, src_port),
269 /* Destination Port */
271 .type = RTE_ACL_FIELD_TYPE_RANGE,
272 .size = sizeof(uint16_t),
275 .offset = sizeof(struct ether_hdr) +
277 sizeof(struct ipv4_hdr) +
278 offsetof(struct tcp_hdr, dst_port),
283 pipeline_firewall_parse_args(struct pipeline_firewall *p,
284 struct pipeline_params *params)
286 uint32_t n_rules_present = 0;
287 uint32_t pkt_type_present = 0;
291 p->n_rules = 4 * 1024;
292 p->n_rule_fields = RTE_DIM(field_format_ipv4);
293 p->field_format = field_format_ipv4;
294 p->field_format_size = sizeof(field_format_ipv4);
296 for (i = 0; i < params->n_args; i++) {
297 char *arg_name = params->args_name[i];
298 char *arg_value = params->args_value[i];
300 if (strcmp(arg_name, "n_rules") == 0) {
305 p->n_rules = atoi(arg_value);
309 if (strcmp(arg_name, "pkt_type") == 0) {
310 if (pkt_type_present)
312 pkt_type_present = 1;
315 if (strcmp(arg_value, "ipv4") == 0) {
316 p->n_rule_fields = RTE_DIM(field_format_ipv4);
317 p->field_format = field_format_ipv4;
318 p->field_format_size =
319 sizeof(field_format_ipv4);
324 if (strcmp(arg_value, "vlan_ipv4") == 0) {
326 RTE_DIM(field_format_vlan_ipv4);
327 p->field_format = field_format_vlan_ipv4;
328 p->field_format_size =
329 sizeof(field_format_vlan_ipv4);
334 if (strcmp(arg_value, "qinq_ipv4") == 0) {
336 RTE_DIM(field_format_qinq_ipv4);
337 p->field_format = field_format_qinq_ipv4;
338 p->field_format_size =
339 sizeof(field_format_qinq_ipv4);
355 pipeline_firewall_init(struct pipeline_params *params,
356 __rte_unused void *arg)
359 struct pipeline_firewall *p_fw;
362 /* Check input arguments */
363 if ((params == NULL) ||
364 (params->n_ports_in == 0) ||
365 (params->n_ports_out == 0))
368 /* Memory allocation */
369 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_firewall));
370 p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
371 p_fw = (struct pipeline_firewall *) p;
375 strcpy(p->name, params->name);
376 p->log_level = params->log_level;
378 PLOG(p, HIGH, "Firewall");
380 /* Parse arguments */
381 if (pipeline_firewall_parse_args(p_fw, params))
386 struct rte_pipeline_params pipeline_params = {
387 .name = params->name,
388 .socket_id = params->socket_id,
392 p->p = rte_pipeline_create(&pipeline_params);
400 p->n_ports_in = params->n_ports_in;
401 for (i = 0; i < p->n_ports_in; i++) {
402 struct rte_pipeline_port_in_params port_params = {
403 .ops = pipeline_port_in_params_get_ops(
404 ¶ms->port_in[i]),
405 .arg_create = pipeline_port_in_params_convert(
406 ¶ms->port_in[i]),
409 .burst_size = params->port_in[i].burst_size,
412 int status = rte_pipeline_port_in_create(p->p,
417 rte_pipeline_free(p->p);
424 p->n_ports_out = params->n_ports_out;
425 for (i = 0; i < p->n_ports_out; i++) {
426 struct rte_pipeline_port_out_params port_params = {
427 .ops = pipeline_port_out_params_get_ops(
428 ¶ms->port_out[i]),
429 .arg_create = pipeline_port_out_params_convert(
430 ¶ms->port_out[i]),
432 .f_action_bulk = NULL,
436 int status = rte_pipeline_port_out_create(p->p,
441 rte_pipeline_free(p->p);
450 struct rte_table_acl_params table_acl_params = {
451 .name = params->name,
452 .n_rules = p_fw->n_rules,
453 .n_rule_fields = p_fw->n_rule_fields,
456 struct rte_pipeline_table_params table_params = {
457 .ops = &rte_table_acl_ops,
458 .arg_create = &table_acl_params,
459 .f_action_hit = NULL,
460 .f_action_miss = NULL,
463 sizeof(struct firewall_table_entry) -
464 sizeof(struct rte_pipeline_table_entry),
469 memcpy(table_acl_params.field_format,
471 p_fw->field_format_size);
473 status = rte_pipeline_table_create(p->p,
478 rte_pipeline_free(p->p);
484 /* Connecting input ports to tables */
485 for (i = 0; i < p->n_ports_in; i++) {
486 int status = rte_pipeline_port_in_connect_to_table(p->p,
491 rte_pipeline_free(p->p);
497 /* Enable input ports */
498 for (i = 0; i < p->n_ports_in; i++) {
499 int status = rte_pipeline_port_in_enable(p->p,
503 rte_pipeline_free(p->p);
509 /* Check pipeline consistency */
510 if (rte_pipeline_check(p->p) < 0) {
511 rte_pipeline_free(p->p);
517 p->n_msgq = params->n_msgq;
518 for (i = 0; i < p->n_msgq; i++)
519 p->msgq_in[i] = params->msgq_in[i];
520 for (i = 0; i < p->n_msgq; i++)
521 p->msgq_out[i] = params->msgq_out[i];
523 /* Message handlers */
524 memcpy(p->handlers, handlers, sizeof(p->handlers));
525 memcpy(p_fw->custom_handlers,
527 sizeof(p_fw->custom_handlers));
533 pipeline_firewall_free(void *pipeline)
535 struct pipeline *p = (struct pipeline *) pipeline;
537 /* Check input arguments */
542 rte_pipeline_free(p->p);
548 pipeline_firewall_track(void *pipeline,
549 __rte_unused uint32_t port_in,
552 struct pipeline *p = (struct pipeline *) pipeline;
554 /* Check input arguments */
556 (port_in >= p->n_ports_in) ||
560 if (p->n_ports_in == 1) {
569 pipeline_firewall_timer(void *pipeline)
571 struct pipeline *p = (struct pipeline *) pipeline;
573 pipeline_msg_req_handle(p);
574 rte_pipeline_flush(p->p);
580 pipeline_firewall_msg_req_custom_handler(struct pipeline *p,
583 struct pipeline_firewall *p_fw = (struct pipeline_firewall *) p;
584 struct pipeline_custom_msg_req *req = msg;
585 pipeline_msg_req_handler f_handle;
587 f_handle = (req->subtype < PIPELINE_FIREWALL_MSG_REQS) ?
588 p_fw->custom_handlers[req->subtype] :
589 pipeline_msg_req_invalid_handler;
591 if (f_handle == NULL)
592 f_handle = pipeline_msg_req_invalid_handler;
594 return f_handle(p, req);
598 pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg)
600 struct pipeline_firewall_add_msg_req *req = msg;
601 struct pipeline_firewall_add_msg_rsp *rsp = msg;
603 struct rte_table_acl_rule_add_params params;
604 struct firewall_table_entry entry = {
606 .action = RTE_PIPELINE_ACTION_PORT,
607 {.port_id = p->port_out_id[req->port_id]},
611 memset(¶ms, 0, sizeof(params));
613 switch (req->key.type) {
614 case PIPELINE_FIREWALL_IPV4_5TUPLE:
615 params.priority = req->priority;
616 params.field_value[0].value.u8 =
617 req->key.key.ipv4_5tuple.proto;
618 params.field_value[0].mask_range.u8 =
619 req->key.key.ipv4_5tuple.proto_mask;
620 params.field_value[1].value.u32 =
621 req->key.key.ipv4_5tuple.src_ip;
622 params.field_value[1].mask_range.u32 =
623 req->key.key.ipv4_5tuple.src_ip_mask;
624 params.field_value[2].value.u32 =
625 req->key.key.ipv4_5tuple.dst_ip;
626 params.field_value[2].mask_range.u32 =
627 req->key.key.ipv4_5tuple.dst_ip_mask;
628 params.field_value[3].value.u16 =
629 req->key.key.ipv4_5tuple.src_port_from;
630 params.field_value[3].mask_range.u16 =
631 req->key.key.ipv4_5tuple.src_port_to;
632 params.field_value[4].value.u16 =
633 req->key.key.ipv4_5tuple.dst_port_from;
634 params.field_value[4].mask_range.u16 =
635 req->key.key.ipv4_5tuple.dst_port_to;
639 rsp->status = -1; /* Error */
643 rsp->status = rte_pipeline_table_entry_add(p->p,
646 (struct rte_pipeline_table_entry *) &entry,
648 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
654 pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg)
656 struct pipeline_firewall_del_msg_req *req = msg;
657 struct pipeline_firewall_del_msg_rsp *rsp = msg;
659 struct rte_table_acl_rule_delete_params params;
661 memset(¶ms, 0, sizeof(params));
663 switch (req->key.type) {
664 case PIPELINE_FIREWALL_IPV4_5TUPLE:
665 params.field_value[0].value.u8 =
666 req->key.key.ipv4_5tuple.proto;
667 params.field_value[0].mask_range.u8 =
668 req->key.key.ipv4_5tuple.proto_mask;
669 params.field_value[1].value.u32 =
670 req->key.key.ipv4_5tuple.src_ip;
671 params.field_value[1].mask_range.u32 =
672 req->key.key.ipv4_5tuple.src_ip_mask;
673 params.field_value[2].value.u32 =
674 req->key.key.ipv4_5tuple.dst_ip;
675 params.field_value[2].mask_range.u32 =
676 req->key.key.ipv4_5tuple.dst_ip_mask;
677 params.field_value[3].value.u16 =
678 req->key.key.ipv4_5tuple.src_port_from;
679 params.field_value[3].mask_range.u16 =
680 req->key.key.ipv4_5tuple.src_port_to;
681 params.field_value[4].value.u16 =
682 req->key.key.ipv4_5tuple.dst_port_from;
683 params.field_value[4].mask_range.u16 =
684 req->key.key.ipv4_5tuple.dst_port_to;
688 rsp->status = -1; /* Error */
692 rsp->status = rte_pipeline_table_entry_delete(p->p,
702 pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg)
704 struct pipeline_firewall_add_default_msg_req *req = msg;
705 struct pipeline_firewall_add_default_msg_rsp *rsp = msg;
707 struct firewall_table_entry default_entry = {
709 .action = RTE_PIPELINE_ACTION_PORT,
710 {.port_id = p->port_out_id[req->port_id]},
714 rsp->status = rte_pipeline_table_default_entry_add(p->p,
716 (struct rte_pipeline_table_entry *) &default_entry,
717 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
723 pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg)
725 struct pipeline_firewall_del_default_msg_rsp *rsp = msg;
727 rsp->status = rte_pipeline_table_default_entry_delete(p->p,
734 struct pipeline_be_ops pipeline_firewall_be_ops = {
735 .f_init = pipeline_firewall_init,
736 .f_free = pipeline_firewall_free,
738 .f_timer = pipeline_firewall_timer,
739 .f_track = pipeline_firewall_track,