X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=examples%2Fip_pipeline%2Fpipeline%2Fpipeline_firewall.c;h=a82e552d71158ff48fcf584f393bcd887e03e970;hb=99c12dcca65d;hp=b70260e30f3cb5813f5a456d1a180781d8c0476a;hpb=bff54484b274dbfe98f189a3bbcc81f9fedb8c5d;p=dpdk.git diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c index b70260e30f..a82e552d71 100644 --- a/examples/ip_pipeline/pipeline/pipeline_firewall.c +++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,284 +30,1421 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#include #include +#include #include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include + +#include "app.h" +#include "pipeline_common_fe.h" +#include "pipeline_firewall.h" +#include "parser.h" -#include -#include -#include +struct app_pipeline_firewall_rule { + struct pipeline_firewall_key key; + int32_t priority; + uint32_t port_id; + void *entry_ptr; -#include "main.h" + TAILQ_ENTRY(app_pipeline_firewall_rule) node; +}; -struct app_core_firewall_message_handle_params { - struct rte_ring *ring_req; - struct rte_ring *ring_resp; +struct app_pipeline_firewall { + /* parameters */ + uint32_t n_ports_in; + uint32_t n_ports_out; - struct rte_pipeline *p; - uint32_t *port_out_id; - uint32_t table_id; + /* rules */ + TAILQ_HEAD(, app_pipeline_firewall_rule) rules; + uint32_t n_rules; + uint32_t default_rule_present; + uint32_t default_rule_port_id; + void *default_rule_entry_ptr; }; static void -app_message_handle(struct app_core_firewall_message_handle_params *params); - -enum { - PROTO_FIELD_IPV4, - SRC_FIELD_IPV4, - DST_FIELD_IPV4, - SRCP_FIELD_IPV4, - DSTP_FIELD_IPV4, - NUM_FIELDS_IPV4 -}; +print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule) +{ + printf("Prio = %" PRId32 " (SA = %" PRIu32 ".%" PRIu32 + ".%" PRIu32 ".%" PRIu32 "/%" PRIu32 ", " + "DA = %" PRIu32 ".%" PRIu32 + ".%"PRIu32 ".%" PRIu32 "/%" PRIu32 ", " + "SP = %" PRIu32 "-%" PRIu32 ", " + "DP = %" PRIu32 "-%" PRIu32 ", " + "Proto = %" PRIu32 " / 0x%" PRIx32 ") => " + "Port = %" PRIu32 " (entry ptr = %p)\n", -struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = { - { - .type = RTE_ACL_FIELD_TYPE_BITMASK, - .size = sizeof(uint8_t), - .field_index = PROTO_FIELD_IPV4, - .input_index = PROTO_FIELD_IPV4, - .offset = sizeof(struct ether_hdr) + - offsetof(struct ipv4_hdr, next_proto_id), - }, - { - .type = RTE_ACL_FIELD_TYPE_MASK, - .size = sizeof(uint32_t), - .field_index = SRC_FIELD_IPV4, - .input_index = SRC_FIELD_IPV4, - .offset = sizeof(struct ether_hdr) + - offsetof(struct ipv4_hdr, src_addr), - }, - { - .type = RTE_ACL_FIELD_TYPE_MASK, - .size = sizeof(uint32_t), - .field_index = DST_FIELD_IPV4, - .input_index = DST_FIELD_IPV4, - .offset = sizeof(struct ether_hdr) + - offsetof(struct ipv4_hdr, dst_addr), - }, - { - .type = RTE_ACL_FIELD_TYPE_RANGE, - .size = sizeof(uint16_t), - .field_index = SRCP_FIELD_IPV4, - .input_index = SRCP_FIELD_IPV4, - .offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr), - }, + rule->priority, + + (rule->key.key.ipv4_5tuple.src_ip >> 24) & 0xFF, + (rule->key.key.ipv4_5tuple.src_ip >> 16) & 0xFF, + (rule->key.key.ipv4_5tuple.src_ip >> 8) & 0xFF, + rule->key.key.ipv4_5tuple.src_ip & 0xFF, + rule->key.key.ipv4_5tuple.src_ip_mask, + + (rule->key.key.ipv4_5tuple.dst_ip >> 24) & 0xFF, + (rule->key.key.ipv4_5tuple.dst_ip >> 16) & 0xFF, + (rule->key.key.ipv4_5tuple.dst_ip >> 8) & 0xFF, + rule->key.key.ipv4_5tuple.dst_ip & 0xFF, + rule->key.key.ipv4_5tuple.dst_ip_mask, + + rule->key.key.ipv4_5tuple.src_port_from, + rule->key.key.ipv4_5tuple.src_port_to, + + rule->key.key.ipv4_5tuple.dst_port_from, + rule->key.key.ipv4_5tuple.dst_port_to, + + rule->key.key.ipv4_5tuple.proto, + rule->key.key.ipv4_5tuple.proto_mask, + + rule->port_id, + rule->entry_ptr); +} + +static struct app_pipeline_firewall_rule * +app_pipeline_firewall_rule_find(struct app_pipeline_firewall *p, + struct pipeline_firewall_key *key) +{ + struct app_pipeline_firewall_rule *r; + + TAILQ_FOREACH(r, &p->rules, node) + if (memcmp(key, + &r->key, + sizeof(struct pipeline_firewall_key)) == 0) + return r; + + return NULL; +} + +static int +app_pipeline_firewall_ls( + struct app_params *app, + uint32_t pipeline_id) +{ + struct app_pipeline_firewall *p; + struct app_pipeline_firewall_rule *rule; + uint32_t n_rules; + int priority; + + /* Check input arguments */ + if (app == NULL) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + n_rules = p->n_rules; + for (priority = 0; n_rules; priority++) + TAILQ_FOREACH(rule, &p->rules, node) + if (rule->priority == priority) { + print_firewall_ipv4_rule(rule); + n_rules--; + } + + if (p->default_rule_present) + printf("Default rule: port %" PRIu32 " (entry ptr = %p)\n", + p->default_rule_port_id, + p->default_rule_entry_ptr); + else + printf("Default rule: DROP\n"); + + printf("\n"); + + return 0; +} + +static void* +app_pipeline_firewall_init(struct pipeline_params *params, + __rte_unused void *arg) +{ + struct app_pipeline_firewall *p; + uint32_t size; + + /* Check input arguments */ + if ((params == NULL) || + (params->n_ports_in == 0) || + (params->n_ports_out == 0)) + return NULL; + + /* Memory allocation */ + size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_firewall)); + p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + if (p == NULL) + return NULL; + + /* Initialization */ + p->n_ports_in = params->n_ports_in; + p->n_ports_out = params->n_ports_out; + + TAILQ_INIT(&p->rules); + p->n_rules = 0; + p->default_rule_present = 0; + p->default_rule_port_id = 0; + p->default_rule_entry_ptr = NULL; + + return (void *) p; +} + +static int +app_pipeline_firewall_free(void *pipeline) +{ + struct app_pipeline_firewall *p = pipeline; + + /* Check input arguments */ + if (p == NULL) + return -1; + + /* Free resources */ + while (!TAILQ_EMPTY(&p->rules)) { + struct app_pipeline_firewall_rule *rule; + + rule = TAILQ_FIRST(&p->rules); + TAILQ_REMOVE(&p->rules, rule, node); + rte_free(rule); + } + + rte_free(p); + return 0; +} + +static int +app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key) +{ + switch (key->type) { + case PIPELINE_FIREWALL_IPV4_5TUPLE: { - .type = RTE_ACL_FIELD_TYPE_RANGE, - .size = sizeof(uint16_t), - .field_index = DSTP_FIELD_IPV4, - .input_index = SRCP_FIELD_IPV4, - .offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) + - sizeof(uint16_t), - }, -}; + uint32_t src_ip_depth = key->key.ipv4_5tuple.src_ip_mask; + uint32_t dst_ip_depth = key->key.ipv4_5tuple.dst_ip_mask; + uint16_t src_port_from = key->key.ipv4_5tuple.src_port_from; + uint16_t src_port_to = key->key.ipv4_5tuple.src_port_to; + uint16_t dst_port_from = key->key.ipv4_5tuple.dst_port_from; + uint16_t dst_port_to = key->key.ipv4_5tuple.dst_port_to; -void -app_main_loop_pipeline_firewall(void) { - struct rte_pipeline_params pipeline_params = { - .name = "pipeline", - .socket_id = rte_socket_id(), - }; - - struct rte_pipeline *p; - uint32_t port_in_id[APP_MAX_PORTS]; - uint32_t port_out_id[APP_MAX_PORTS]; - uint32_t table_id; - uint32_t i; + uint32_t src_ip_netmask = 0; + uint32_t dst_ip_netmask = 0; + + if ((src_ip_depth > 32) || + (dst_ip_depth > 32) || + (src_port_from > src_port_to) || + (dst_port_from > dst_port_to)) + return -1; - uint32_t core_id = rte_lcore_id(); - struct app_core_params *core_params = app_get_core_params(core_id); - struct app_core_firewall_message_handle_params mh_params; + if (src_ip_depth) + src_ip_netmask = (~0U) << (32 - src_ip_depth); - if ((core_params == NULL) || (core_params->core_type != APP_CORE_FW)) - rte_panic("Core %u misconfiguration\n", core_id); + if (dst_ip_depth) + dst_ip_netmask = ((~0U) << (32 - dst_ip_depth)); - RTE_LOG(INFO, USER1, "Core %u is doing firewall\n", core_id); + key->key.ipv4_5tuple.src_ip &= src_ip_netmask; + key->key.ipv4_5tuple.dst_ip &= dst_ip_netmask; + + return 0; + } + + default: + return -1; + } +} + +int +app_pipeline_firewall_load_file(char *filename, + struct pipeline_firewall_key *keys, + uint32_t *priorities, + uint32_t *port_ids, + uint32_t *n_keys, + uint32_t *line) +{ + FILE *f = NULL; + char file_buf[1024]; + uint32_t i, l; + + /* Check input arguments */ + if ((filename == NULL) || + (keys == NULL) || + (priorities == NULL) || + (port_ids == NULL) || + (n_keys == NULL) || + (*n_keys == 0) || + (line == NULL)) { + if (line) + *line = 0; + return -1; + } + + /* Open input file */ + f = fopen(filename, "r"); + if (f == NULL) { + *line = 0; + return -1; + } - /* Pipeline configuration */ - p = rte_pipeline_create(&pipeline_params); + /* Read file */ + for (i = 0, l = 1; i < *n_keys; l++) { + char *tokens[32]; + uint32_t n_tokens = RTE_DIM(tokens); + + uint32_t priority = 0; + struct in_addr sipaddr; + uint32_t sipdepth = 0; + struct in_addr dipaddr; + uint32_t dipdepth = 0; + uint16_t sport0 = 0; + uint16_t sport1 = 0; + uint16_t dport0 = 0; + uint16_t dport1 = 0; + uint8_t proto = 0; + uint8_t protomask = 0; + uint32_t port_id = 0; + + int status; + + if (fgets(file_buf, sizeof(file_buf), f) == NULL) + break; + + status = parse_tokenize_string(file_buf, tokens, &n_tokens); + if (status) + goto error1; + + if ((n_tokens == 0) || (tokens[0][0] == '#')) + continue; + + if ((n_tokens != 15) || + strcmp(tokens[0], "priority") || + parser_read_uint32(&priority, tokens[1]) || + strcmp(tokens[2], "ipv4") || + parse_ipv4_addr(tokens[3], &sipaddr) || + parser_read_uint32(&sipdepth, tokens[4]) || + parse_ipv4_addr(tokens[5], &dipaddr) || + parser_read_uint32(&dipdepth, tokens[6]) || + parser_read_uint16(&sport0, tokens[7]) || + parser_read_uint16(&sport1, tokens[8]) || + parser_read_uint16(&dport0, tokens[9]) || + parser_read_uint16(&dport1, tokens[10]) || + parser_read_uint8(&proto, tokens[11]) || + parser_read_uint8_hex(&protomask, tokens[12]) || + strcmp(tokens[13], "port") || + parser_read_uint32(&port_id, tokens[14])) + goto error1; + + keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE; + keys[i].key.ipv4_5tuple.src_ip = + rte_be_to_cpu_32(sipaddr.s_addr); + keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth; + keys[i].key.ipv4_5tuple.dst_ip = + rte_be_to_cpu_32(dipaddr.s_addr); + keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth; + keys[i].key.ipv4_5tuple.src_port_from = sport0; + keys[i].key.ipv4_5tuple.src_port_to = sport1; + keys[i].key.ipv4_5tuple.dst_port_from = dport0; + keys[i].key.ipv4_5tuple.dst_port_to = dport1; + keys[i].key.ipv4_5tuple.proto = proto; + keys[i].key.ipv4_5tuple.proto_mask = protomask; + + port_ids[i] = port_id; + priorities[i] = priority; + + if (app_pipeline_firewall_key_check_and_normalize(&keys[i])) + goto error1; + + i++; + } + + /* Close file */ + *n_keys = i; + fclose(f); + return 0; + +error1: + *line = l; + fclose(f); + return -1; +} + +int +app_pipeline_firewall_add_rule(struct app_params *app, + uint32_t pipeline_id, + struct pipeline_firewall_key *key, + uint32_t priority, + uint32_t port_id) +{ + struct app_pipeline_firewall *p; + struct app_pipeline_firewall_rule *rule; + struct pipeline_firewall_add_msg_req *req; + struct pipeline_firewall_add_msg_rsp *rsp; + int new_rule; + + /* Check input arguments */ + if ((app == NULL) || + (key == NULL) || + (key->type != PIPELINE_FIREWALL_IPV4_5TUPLE)) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); if (p == NULL) - rte_panic("Unable to configure the pipeline\n"); - - /* Input port configuration */ - for (i = 0; i < app.n_ports; i++) { - struct rte_port_ring_reader_params port_ring_params = { - .ring = app.rings[core_params->swq_in[i]], - }; - - struct rte_pipeline_port_in_params port_params = { - .ops = &rte_port_ring_reader_ops, - .arg_create = (void *) &port_ring_params, - .f_action = NULL, - .arg_ah = NULL, - .burst_size = app.bsz_swq_rd, - }; - - if (rte_pipeline_port_in_create(p, &port_params, - &port_in_id[i])) - rte_panic("Unable to configure input port for " - "ring %d\n", i); + return -1; + + if (port_id >= p->n_ports_out) + return -1; + + if (app_pipeline_firewall_key_check_and_normalize(key) != 0) + return -1; + + /* Find existing rule or allocate new rule */ + rule = app_pipeline_firewall_rule_find(p, key); + new_rule = (rule == NULL); + if (rule == NULL) { + rule = rte_malloc(NULL, sizeof(*rule), RTE_CACHE_LINE_SIZE); + + if (rule == NULL) + return -1; } - /* Output port configuration */ - for (i = 0; i < app.n_ports; i++) { - struct rte_port_ring_writer_params port_ring_params = { - .ring = app.rings[core_params->swq_out[i]], - .tx_burst_sz = app.bsz_swq_wr, - }; - - struct rte_pipeline_port_out_params port_params = { - .ops = &rte_port_ring_writer_ops, - .arg_create = (void *) &port_ring_params, - .f_action = NULL, - .f_action_bulk = NULL, - .arg_ah = NULL, - }; - - if (rte_pipeline_port_out_create(p, &port_params, - &port_out_id[i])) - rte_panic("Unable to configure output port for " - "ring %d\n", i); + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) { + if (new_rule) + rte_free(rule); + return -1; } - /* Table configuration */ - { - struct rte_table_acl_params table_acl_params = { - .name = "test", /* unique identifier for acl contexts */ - .n_rules = app.max_firewall_rules, - .n_rule_fields = DIM(ipv4_field_formats), - }; - - struct rte_pipeline_table_params table_params = { - .ops = &rte_table_acl_ops, - .arg_create = &table_acl_params, - .f_action_hit = NULL, - .f_action_miss = NULL, - .arg_ah = NULL, - .action_data_size = 0, - }; - - memcpy(table_acl_params.field_format, ipv4_field_formats, - sizeof(ipv4_field_formats)); - - if (rte_pipeline_table_create(p, &table_params, &table_id)) - rte_panic("Unable to configure the ACL table\n"); + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD; + memcpy(&req->key, key, sizeof(*key)); + req->priority = priority; + req->port_id = port_id; + + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) { + if (new_rule) + rte_free(rule); + return -1; + } + + /* Read response and write rule */ + if (rsp->status || + (rsp->entry_ptr == NULL) || + ((new_rule == 0) && (rsp->key_found == 0)) || + ((new_rule == 1) && (rsp->key_found == 1))) { + app_msg_free(app, rsp); + if (new_rule) + rte_free(rule); + return -1; + } + + memcpy(&rule->key, key, sizeof(*key)); + rule->priority = priority; + rule->port_id = port_id; + rule->entry_ptr = rsp->entry_ptr; + + /* Commit rule */ + if (new_rule) { + TAILQ_INSERT_TAIL(&p->rules, rule, node); + p->n_rules++; + } + + print_firewall_ipv4_rule(rule); + + /* Free response */ + app_msg_free(app, rsp); + + return 0; +} + +int +app_pipeline_firewall_delete_rule(struct app_params *app, + uint32_t pipeline_id, + struct pipeline_firewall_key *key) +{ + struct app_pipeline_firewall *p; + struct app_pipeline_firewall_rule *rule; + struct pipeline_firewall_del_msg_req *req; + struct pipeline_firewall_del_msg_rsp *rsp; + + /* Check input arguments */ + if ((app == NULL) || + (key == NULL) || + (key->type != PIPELINE_FIREWALL_IPV4_5TUPLE)) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + if (app_pipeline_firewall_key_check_and_normalize(key) != 0) + return -1; + + /* Find rule */ + rule = app_pipeline_firewall_rule_find(p, key); + if (rule == NULL) + return 0; + + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) + return -1; + + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL; + memcpy(&req->key, key, sizeof(*key)); + + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) + return -1; + + /* Read response */ + if (rsp->status || !rsp->key_found) { + app_msg_free(app, rsp); + return -1; } - /* Interconnecting ports and tables */ - for (i = 0; i < app.n_ports; i++) - if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], - table_id)) - rte_panic("Unable to connect input port %u to " - "table %u\n", port_in_id[i], table_id); - - /* Enable input ports */ - for (i = 0; i < app.n_ports; i++) - if (rte_pipeline_port_in_enable(p, port_in_id[i])) - rte_panic("Unable to enable input port %u\n", - port_in_id[i]); - - /* Check pipeline consistency */ - if (rte_pipeline_check(p) < 0) - rte_panic("Pipeline consistency check failed\n"); - - /* Message handling */ - mh_params.ring_req = app_get_ring_req( - app_get_first_core_id(APP_CORE_FW)); - mh_params.ring_resp = app_get_ring_resp( - app_get_first_core_id(APP_CORE_FW)); - mh_params.p = p; - mh_params.port_out_id = port_out_id; - mh_params.table_id = table_id; - - /* Run-time */ - for (i = 0; ; i++) { - rte_pipeline_run(p); - - if ((i & APP_FLUSH) == 0) { - rte_pipeline_flush(p); - app_message_handle(&mh_params); + /* Remove rule */ + TAILQ_REMOVE(&p->rules, rule, node); + p->n_rules--; + rte_free(rule); + + /* Free response */ + app_msg_free(app, rsp); + + return 0; +} + +int +app_pipeline_firewall_add_bulk(struct app_params *app, + uint32_t pipeline_id, + struct pipeline_firewall_key *keys, + uint32_t n_keys, + uint32_t *priorities, + uint32_t *port_ids) +{ + struct app_pipeline_firewall *p; + struct pipeline_firewall_add_bulk_msg_req *req; + struct pipeline_firewall_add_bulk_msg_rsp *rsp; + + struct app_pipeline_firewall_rule **rules; + int *new_rules; + + int *keys_found; + void **entries_ptr; + + uint32_t i; + int status = 0; + + /* Check input arguments */ + if (app == NULL) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + rules = rte_malloc(NULL, + n_keys * sizeof(struct app_pipeline_firewall_rule *), + RTE_CACHE_LINE_SIZE); + if (rules == NULL) + return -1; + + new_rules = rte_malloc(NULL, + n_keys * sizeof(int), + RTE_CACHE_LINE_SIZE); + if (new_rules == NULL) { + rte_free(rules); + return -1; + } + + /* check data integrity and add to rule list */ + for (i = 0; i < n_keys; i++) { + if (port_ids[i] >= p->n_ports_out) { + rte_free(rules); + rte_free(new_rules); + return -1; + } + + if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) { + rte_free(rules); + rte_free(new_rules); + return -1; + } + + rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]); + new_rules[i] = (rules[i] == NULL); + if (rules[i] == NULL) { + rules[i] = rte_malloc(NULL, + sizeof(*rules[i]), + RTE_CACHE_LINE_SIZE); + + if (rules[i] == NULL) { + uint32_t j; + + for (j = 0; j <= i; j++) + if (new_rules[j]) + rte_free(rules[j]); + + rte_free(rules); + rte_free(new_rules); + return -1; + } } } + + keys_found = rte_malloc(NULL, + n_keys * sizeof(int), + RTE_CACHE_LINE_SIZE); + if (keys_found == NULL) { + uint32_t j; + + for (j = 0; j < n_keys; j++) + if (new_rules[j]) + rte_free(rules[j]); + + rte_free(rules); + rte_free(new_rules); + return -1; + } + + entries_ptr = rte_malloc(NULL, + n_keys * sizeof(struct rte_pipeline_table_entry *), + RTE_CACHE_LINE_SIZE); + if (entries_ptr == NULL) { + uint32_t j; + + for (j = 0; j < n_keys; j++) + if (new_rules[j]) + rte_free(rules[j]); + + rte_free(rules); + rte_free(new_rules); + rte_free(keys_found); + return -1; + } + for (i = 0; i < n_keys; i++) { + entries_ptr[i] = rte_malloc(NULL, + sizeof(struct rte_pipeline_table_entry), + RTE_CACHE_LINE_SIZE); + + if (entries_ptr[i] == NULL) { + uint32_t j; + + for (j = 0; j < n_keys; j++) + if (new_rules[j]) + rte_free(rules[j]); + + for (j = 0; j <= i; j++) + rte_free(entries_ptr[j]); + + rte_free(rules); + rte_free(new_rules); + rte_free(keys_found); + rte_free(entries_ptr); + return -1; + } + } + + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) { + uint32_t j; + + for (j = 0; j < n_keys; j++) + if (new_rules[j]) + rte_free(rules[j]); + + for (j = 0; j < n_keys; j++) + rte_free(entries_ptr[j]); + + rte_free(rules); + rte_free(new_rules); + rte_free(keys_found); + rte_free(entries_ptr); + return -1; + } + + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_BULK; + + req->keys = keys; + req->n_keys = n_keys; + req->port_ids = port_ids; + req->priorities = priorities; + req->keys_found = keys_found; + req->entries_ptr = entries_ptr; + + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) { + uint32_t j; + + for (j = 0; j < n_keys; j++) + if (new_rules[j]) + rte_free(rules[j]); + + for (j = 0; j < n_keys; j++) + rte_free(entries_ptr[j]); + + rte_free(rules); + rte_free(new_rules); + rte_free(keys_found); + rte_free(entries_ptr); + return -1; + } + + if (rsp->status) { + for (i = 0; i < n_keys; i++) + if (new_rules[i]) + rte_free(rules[i]); + + for (i = 0; i < n_keys; i++) + rte_free(entries_ptr[i]); + + status = -1; + goto cleanup; + } + + for (i = 0; i < n_keys; i++) { + if (entries_ptr[i] == NULL || + ((new_rules[i] == 0) && (keys_found[i] == 0)) || + ((new_rules[i] == 1) && (keys_found[i] == 1))) { + for (i = 0; i < n_keys; i++) + if (new_rules[i]) + rte_free(rules[i]); + + for (i = 0; i < n_keys; i++) + rte_free(entries_ptr[i]); + + status = -1; + goto cleanup; + } + } + + for (i = 0; i < n_keys; i++) { + memcpy(&rules[i]->key, &keys[i], sizeof(keys[i])); + rules[i]->priority = priorities[i]; + rules[i]->port_id = port_ids[i]; + rules[i]->entry_ptr = entries_ptr[i]; + + /* Commit rule */ + if (new_rules[i]) { + TAILQ_INSERT_TAIL(&p->rules, rules[i], node); + p->n_rules++; + } + + print_firewall_ipv4_rule(rules[i]); + } + +cleanup: + app_msg_free(app, rsp); + rte_free(rules); + rte_free(new_rules); + rte_free(keys_found); + rte_free(entries_ptr); + + return status; } -void -app_message_handle(struct app_core_firewall_message_handle_params *params) +int +app_pipeline_firewall_delete_bulk(struct app_params *app, + uint32_t pipeline_id, + struct pipeline_firewall_key *keys, + uint32_t n_keys) { - struct rte_ring *ring_req = params->ring_req; - struct rte_ring *ring_resp; - struct rte_mbuf *msg; - struct app_msg_req *req; - struct app_msg_resp *resp; - struct rte_pipeline *p; - uint32_t *port_out_id; - uint32_t table_id; - int result; - - /* Read request message */ - result = rte_ring_sc_dequeue(ring_req, (void **) &msg); - if (result != 0) - return; + struct app_pipeline_firewall *p; + struct pipeline_firewall_del_bulk_msg_req *req; + struct pipeline_firewall_del_bulk_msg_rsp *rsp; - ring_resp = params->ring_resp; - p = params->p; - port_out_id = params->port_out_id; - table_id = params->table_id; + struct app_pipeline_firewall_rule **rules; + int *keys_found; - /* Handle request */ - req = (struct app_msg_req *)rte_ctrlmbuf_data(msg); - switch (req->type) { - case APP_MSG_REQ_PING: - { - result = 0; - break; + uint32_t i; + int status = 0; + + /* Check input arguments */ + if (app == NULL) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + rules = rte_malloc(NULL, + n_keys * sizeof(struct app_pipeline_firewall_rule *), + RTE_CACHE_LINE_SIZE); + if (rules == NULL) + return -1; + + for (i = 0; i < n_keys; i++) { + if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) { + return -1; + } + + rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]); } - case APP_MSG_REQ_FW_ADD: - { - struct rte_pipeline_table_entry entry = { - .action = RTE_PIPELINE_ACTION_PORT, - {.port_id = port_out_id[req->firewall_add.port]}, - }; + keys_found = rte_malloc(NULL, + n_keys * sizeof(int), + RTE_CACHE_LINE_SIZE); + if (keys_found == NULL) { + rte_free(rules); + return -1; + } - struct rte_pipeline_table_entry *entry_ptr; + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) { + rte_free(rules); + rte_free(keys_found); + return -1; + } + + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_BULK; - int key_found; + req->keys = keys; + req->n_keys = n_keys; + req->keys_found = keys_found; - result = rte_pipeline_table_entry_add(p, table_id, - &req->firewall_add.add_params, &entry, &key_found, - &entry_ptr); - break; + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) { + rte_free(rules); + rte_free(keys_found); + return -1; } - case APP_MSG_REQ_FW_DEL: - { - int key_found; + if (rsp->status) { + status = -1; + goto cleanup; + } - result = rte_pipeline_table_entry_delete(p, table_id, - &req->firewall_del.delete_params, &key_found, NULL); - break; + for (i = 0; i < n_keys; i++) { + if (keys_found[i] == 0) { + status = -1; + goto cleanup; + } } - default: - rte_panic("FW unrecognized message type (%u)\n", req->type); + for (i = 0; i < n_keys; i++) { + TAILQ_REMOVE(&p->rules, rules[i], node); + p->n_rules--; + rte_free(rules[i]); } - /* Fill in response message */ - resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg); - resp->result = result; +cleanup: + app_msg_free(app, rsp); + rte_free(rules); + rte_free(keys_found); - /* Send response */ - do { - result = rte_ring_sp_enqueue(ring_resp, (void *) msg); - } while (result == -ENOBUFS); + return status; } + +int +app_pipeline_firewall_add_default_rule(struct app_params *app, + uint32_t pipeline_id, + uint32_t port_id) +{ + struct app_pipeline_firewall *p; + struct pipeline_firewall_add_default_msg_req *req; + struct pipeline_firewall_add_default_msg_rsp *rsp; + + /* Check input arguments */ + if (app == NULL) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + if (port_id >= p->n_ports_out) + return -1; + + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) + return -1; + + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT; + req->port_id = port_id; + + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) + return -1; + + /* Read response and write rule */ + if (rsp->status || (rsp->entry_ptr == NULL)) { + app_msg_free(app, rsp); + return -1; + } + + p->default_rule_port_id = port_id; + p->default_rule_entry_ptr = rsp->entry_ptr; + + /* Commit rule */ + p->default_rule_present = 1; + + /* Free response */ + app_msg_free(app, rsp); + + return 0; +} + +int +app_pipeline_firewall_delete_default_rule(struct app_params *app, + uint32_t pipeline_id) +{ + struct app_pipeline_firewall *p; + struct pipeline_firewall_del_default_msg_req *req; + struct pipeline_firewall_del_default_msg_rsp *rsp; + + /* Check input arguments */ + if (app == NULL) + return -1; + + p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall); + if (p == NULL) + return -1; + + /* Allocate and write request */ + req = app_msg_alloc(app); + if (req == NULL) + return -1; + + req->type = PIPELINE_MSG_REQ_CUSTOM; + req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT; + + /* Send request and wait for response */ + rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT); + if (rsp == NULL) + return -1; + + /* Read response and write rule */ + if (rsp->status) { + app_msg_free(app, rsp); + return -1; + } + + /* Commit rule */ + p->default_rule_present = 0; + + /* Free response */ + app_msg_free(app, rsp); + + return 0; +} + +/* + * firewall + * + * firewall add: + * p firewall add priority + * ipv4 + * + * port + * Note: is a hex value + * + * p firewall add bulk + * + * firewall add default: + * p firewall add default + * + * firewall del: + * p firewall del + * ipv4 + * + * + * p firewall del bulk + * + * firewall del default: + * p firewall del default + * + * firewall ls: + * p firewall ls + */ + +struct cmd_firewall_result { + cmdline_fixed_string_t p_string; + uint32_t pipeline_id; + cmdline_fixed_string_t firewall_string; + cmdline_multi_string_t multi_string; +}; + +static void cmd_firewall_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + void *data) +{ + struct cmd_firewall_result *params = parsed_result; + struct app_params *app = data; + int status; + + char *tokens[17]; + uint32_t n_tokens = RTE_DIM(tokens); + + status = parse_tokenize_string(params->multi_string, tokens, &n_tokens); + if (status) { + printf(CMD_MSG_TOO_MANY_ARGS, "firewall"); + return; + } + + /* firewall add */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "add") == 0) && + (strcmp(tokens[1], "priority") == 0)) { + struct pipeline_firewall_key key; + uint32_t priority; + struct in_addr sipaddr; + uint32_t sipdepth; + struct in_addr dipaddr; + uint32_t dipdepth; + uint16_t sport0; + uint16_t sport1; + uint16_t dport0; + uint16_t dport1; + uint8_t proto; + uint8_t protomask; + uint32_t port_id; + + memset(&key, 0, sizeof(key)); + + if (n_tokens != 16) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall add"); + return; + } + + if (parser_read_uint32(&priority, tokens[2])) { + printf(CMD_MSG_INVALID_ARG, "priority"); + return; + } + + if (strcmp(tokens[3], "ipv4")) { + printf(CMD_MSG_ARG_NOT_FOUND, "ipv4"); + return; + } + + if (parse_ipv4_addr(tokens[4], &sipaddr)) { + printf(CMD_MSG_INVALID_ARG, "sipaddr"); + return; + } + + if (parser_read_uint32(&sipdepth, tokens[5])) { + printf(CMD_MSG_INVALID_ARG, "sipdepth"); + return; + } + + if (parse_ipv4_addr(tokens[6], &dipaddr)) { + printf(CMD_MSG_INVALID_ARG, "dipaddr"); + return; + } + + if (parser_read_uint32(&dipdepth, tokens[7])) { + printf(CMD_MSG_INVALID_ARG, "dipdepth"); + return; + } + + if (parser_read_uint16(&sport0, tokens[8])) { + printf(CMD_MSG_INVALID_ARG, "sport0"); + return; + } + + if (parser_read_uint16(&sport1, tokens[9])) { + printf(CMD_MSG_INVALID_ARG, "sport1"); + return; + } + + if (parser_read_uint16(&dport0, tokens[10])) { + printf(CMD_MSG_INVALID_ARG, "dport0"); + return; + } + + if (parser_read_uint16(&dport1, tokens[11])) { + printf(CMD_MSG_INVALID_ARG, "dport1"); + return; + } + + if (parser_read_uint8(&proto, tokens[12])) { + printf(CMD_MSG_INVALID_ARG, "proto"); + return; + } + + if (parser_read_uint8_hex(&protomask, tokens[13])) { + printf(CMD_MSG_INVALID_ARG, "protomask"); + return; + } + + if (strcmp(tokens[14], "port")) { + printf(CMD_MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (parser_read_uint32(&port_id, tokens[15])) { + printf(CMD_MSG_INVALID_ARG, "portid"); + return; + } + + key.type = PIPELINE_FIREWALL_IPV4_5TUPLE; + key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr); + key.key.ipv4_5tuple.src_ip_mask = sipdepth; + key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr); + key.key.ipv4_5tuple.dst_ip_mask = dipdepth; + key.key.ipv4_5tuple.src_port_from = sport0; + key.key.ipv4_5tuple.src_port_to = sport1; + key.key.ipv4_5tuple.dst_port_from = dport0; + key.key.ipv4_5tuple.dst_port_to = dport1; + key.key.ipv4_5tuple.proto = proto; + key.key.ipv4_5tuple.proto_mask = protomask; + + status = app_pipeline_firewall_add_rule(app, + params->pipeline_id, + &key, + priority, + port_id); + if (status) + printf(CMD_MSG_FAIL, "firewall add"); + + return; + } /* firewall add */ + + /* firewall add bulk */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "add") == 0) && + (strcmp(tokens[1], "bulk") == 0)) { + struct pipeline_firewall_key *keys; + uint32_t *priorities, *port_ids, n_keys, line; + char *filename; + + if (n_tokens != 3) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk"); + return; + } + + filename = tokens[2]; + + n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE; + keys = malloc(n_keys * sizeof(struct pipeline_firewall_key)); + if (keys == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + return; + } + memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key)); + + priorities = malloc(n_keys * sizeof(uint32_t)); + if (priorities == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + free(keys); + return; + } + + port_ids = malloc(n_keys * sizeof(uint32_t)); + if (port_ids == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + free(priorities); + free(keys); + return; + } + + status = app_pipeline_firewall_load_file(filename, + keys, + priorities, + port_ids, + &n_keys, + &line); + if (status != 0) { + printf(CMD_MSG_FILE_ERR, filename, line); + free(port_ids); + free(priorities); + free(keys); + return; + } + + status = app_pipeline_firewall_add_bulk(app, + params->pipeline_id, + keys, + n_keys, + priorities, + port_ids); + if (status) + printf(CMD_MSG_FAIL, "firewall add bulk"); + + free(keys); + free(priorities); + free(port_ids); + return; + } /* firewall add bulk */ + + /* firewall add default */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "add") == 0) && + (strcmp(tokens[1], "default") == 0)) { + uint32_t port_id; + + if (n_tokens != 3) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall add default"); + return; + } + + if (parser_read_uint32(&port_id, tokens[2])) { + printf(CMD_MSG_INVALID_ARG, "portid"); + return; + } + + status = app_pipeline_firewall_add_default_rule(app, + params->pipeline_id, + port_id); + if (status) + printf(CMD_MSG_FAIL, "firewall add default"); + + return; + } /* firewall add default */ + + /* firewall del */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "del") == 0) && + (strcmp(tokens[1], "ipv4") == 0)) { + struct pipeline_firewall_key key; + struct in_addr sipaddr; + uint32_t sipdepth; + struct in_addr dipaddr; + uint32_t dipdepth; + uint16_t sport0; + uint16_t sport1; + uint16_t dport0; + uint16_t dport1; + uint8_t proto; + uint8_t protomask; + + memset(&key, 0, sizeof(key)); + + if (n_tokens != 12) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall del"); + return; + } + + if (parse_ipv4_addr(tokens[2], &sipaddr)) { + printf(CMD_MSG_INVALID_ARG, "sipaddr"); + return; + } + + if (parser_read_uint32(&sipdepth, tokens[3])) { + printf(CMD_MSG_INVALID_ARG, "sipdepth"); + return; + } + + if (parse_ipv4_addr(tokens[4], &dipaddr)) { + printf(CMD_MSG_INVALID_ARG, "dipaddr"); + return; + } + + if (parser_read_uint32(&dipdepth, tokens[5])) { + printf(CMD_MSG_INVALID_ARG, "dipdepth"); + return; + } + + if (parser_read_uint16(&sport0, tokens[6])) { + printf(CMD_MSG_INVALID_ARG, "sport0"); + return; + } + + if (parser_read_uint16(&sport1, tokens[7])) { + printf(CMD_MSG_INVALID_ARG, "sport1"); + return; + } + + if (parser_read_uint16(&dport0, tokens[8])) { + printf(CMD_MSG_INVALID_ARG, "dport0"); + return; + } + + if (parser_read_uint16(&dport1, tokens[9])) { + printf(CMD_MSG_INVALID_ARG, "dport1"); + return; + } + + if (parser_read_uint8(&proto, tokens[10])) { + printf(CMD_MSG_INVALID_ARG, "proto"); + return; + } + + if (parser_read_uint8_hex(&protomask, tokens[11])) { + printf(CMD_MSG_INVALID_ARG, "protomask"); + return; + } + + key.type = PIPELINE_FIREWALL_IPV4_5TUPLE; + key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr); + key.key.ipv4_5tuple.src_ip_mask = sipdepth; + key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr); + key.key.ipv4_5tuple.dst_ip_mask = dipdepth; + key.key.ipv4_5tuple.src_port_from = sport0; + key.key.ipv4_5tuple.src_port_to = sport1; + key.key.ipv4_5tuple.dst_port_from = dport0; + key.key.ipv4_5tuple.dst_port_to = dport1; + key.key.ipv4_5tuple.proto = proto; + key.key.ipv4_5tuple.proto_mask = protomask; + + status = app_pipeline_firewall_delete_rule(app, + params->pipeline_id, + &key); + if (status) + printf(CMD_MSG_FAIL, "firewall del"); + + return; + } /* firewall del */ + + /* firewall del bulk */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "del") == 0) && + (strcmp(tokens[1], "bulk") == 0)) { + struct pipeline_firewall_key *keys; + uint32_t *priorities, *port_ids, n_keys, line; + char *filename; + + if (n_tokens != 3) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk"); + return; + } + + filename = tokens[2]; + + n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE; + keys = malloc(n_keys * sizeof(struct pipeline_firewall_key)); + if (keys == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + return; + } + memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key)); + + priorities = malloc(n_keys * sizeof(uint32_t)); + if (priorities == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + free(keys); + return; + } + + port_ids = malloc(n_keys * sizeof(uint32_t)); + if (port_ids == NULL) { + printf(CMD_MSG_OUT_OF_MEMORY); + free(priorities); + free(keys); + return; + } + + status = app_pipeline_firewall_load_file(filename, + keys, + priorities, + port_ids, + &n_keys, + &line); + if (status != 0) { + printf(CMD_MSG_FILE_ERR, filename, line); + free(port_ids); + free(priorities); + free(keys); + return; + } + + status = app_pipeline_firewall_delete_bulk(app, + params->pipeline_id, + keys, + n_keys); + if (status) + printf(CMD_MSG_FAIL, "firewall del bulk"); + + free(port_ids); + free(priorities); + free(keys); + return; + } /* firewall del bulk */ + + /* firewall del default */ + if ((n_tokens >= 2) && + (strcmp(tokens[0], "del") == 0) && + (strcmp(tokens[1], "default") == 0)) { + if (n_tokens != 2) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall del default"); + return; + } + + status = app_pipeline_firewall_delete_default_rule(app, + params->pipeline_id); + if (status) + printf(CMD_MSG_FAIL, "firewall del default"); + + return; + + } /* firewall del default */ + + /* firewall ls */ + if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) { + if (n_tokens != 1) { + printf(CMD_MSG_MISMATCH_ARGS, "firewall ls"); + return; + } + + status = app_pipeline_firewall_ls(app, params->pipeline_id); + if (status) + printf(CMD_MSG_FAIL, "firewall ls"); + + return; + } /* firewall ls */ + + printf(CMD_MSG_MISMATCH_ARGS, "firewall"); +} + +static cmdline_parse_token_string_t cmd_firewall_p_string = + TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p"); + +static cmdline_parse_token_num_t cmd_firewall_pipeline_id = + TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32); + +static cmdline_parse_token_string_t cmd_firewall_firewall_string = + TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string, + "firewall"); + +static cmdline_parse_token_string_t cmd_firewall_multi_string = + TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string, + TOKEN_STRING_MULTI); + +static cmdline_parse_inst_t cmd_firewall = { + .f = cmd_firewall_parsed, + .data = NULL, + .help_str = "firewall add / add bulk / add default / del / del bulk" + " / del default / ls", + .tokens = { + (void *) &cmd_firewall_p_string, + (void *) &cmd_firewall_pipeline_id, + (void *) &cmd_firewall_firewall_string, + (void *) &cmd_firewall_multi_string, + NULL, + }, +}; + +static cmdline_parse_ctx_t pipeline_cmds[] = { + (cmdline_parse_inst_t *) &cmd_firewall, + NULL, +}; + +static struct pipeline_fe_ops pipeline_firewall_fe_ops = { + .f_init = app_pipeline_firewall_init, + .f_post_init = NULL, + .f_free = app_pipeline_firewall_free, + .f_track = app_pipeline_track_default, + .cmds = pipeline_cmds, +}; + +struct pipeline_type pipeline_firewall = { + .name = "FIREWALL", + .be_ops = &pipeline_firewall_be_ops, + .fe_ops = &pipeline_firewall_fe_ops, +};