/*- * BSD LICENSE * * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (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 "app.h" #include "pipeline_common_fe.h" #include "pipeline_firewall.h" #include "parser.h" struct app_pipeline_firewall_rule { struct pipeline_firewall_key key; int32_t priority; uint32_t port_id; void *entry_ptr; TAILQ_ENTRY(app_pipeline_firewall_rule) node; }; struct app_pipeline_firewall { /* parameters */ uint32_t n_ports_in; uint32_t n_ports_out; /* 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 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", 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: { 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; 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; if (src_ip_depth) src_ip_netmask = (~0U) << (32 - src_ip_depth); if (dst_ip_depth) dst_ip_netmask = ((~0U) << (32 - dst_ip_depth)); 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; } /* 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) 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; } /* Allocate and write request */ req = app_msg_alloc(app); if (req == NULL) { if (new_rule) rte_free(rule); return -1; } 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; } /* 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; } int app_pipeline_firewall_delete_bulk(struct app_params *app, uint32_t pipeline_id, struct pipeline_firewall_key *keys, uint32_t n_keys) { struct app_pipeline_firewall *p; struct pipeline_firewall_del_bulk_msg_req *req; struct pipeline_firewall_del_bulk_msg_rsp *rsp; struct app_pipeline_firewall_rule **rules; int *keys_found; 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]); } keys_found = rte_malloc(NULL, n_keys * sizeof(int), RTE_CACHE_LINE_SIZE); if (keys_found == NULL) { rte_free(rules); return -1; } /* 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; req->keys = keys; req->n_keys = n_keys; req->keys_found = keys_found; /* 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; } if (rsp->status) { status = -1; goto cleanup; } for (i = 0; i < n_keys; i++) { if (keys_found[i] == 0) { status = -1; goto cleanup; } } for (i = 0; i < n_keys; i++) { TAILQ_REMOVE(&p->rules, rules[i], node); p->n_rules--; rte_free(rules[i]); } cleanup: app_msg_free(app, rsp); rte_free(rules); rte_free(keys_found); 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, };