From a003a406fca043388205f9c45f86895be81f798d Mon Sep 17 00:00:00 2001 From: Dennis Afanasev <32916582+dennisafa@users.noreply.github.com> Date: Thu, 23 May 2019 09:45:45 -0400 Subject: [PATCH] Add a Firewall NF which uses the DPDK LPM Library (#80) The firewall NF drops or forwards packets based on rules provided in the json file. This is achieved using DPDK's LPM (longest prefix matching) library. Default behavior is to drop a packet unless the packet matches a rule. The NF also has a debug mode to print decisions for every packet and an inverse match mode where default behavior is to forward a packet if it is not found in the table. Commit log: * Syncing with current * Updates for ubuntu 18 * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Updates * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update onvm_config_common.c * Update onvm_config_common.c * Updates * Update onvm_config_common.c * Updates * updates * Update onvm_config_common.c * Update onvm_config_common.c * Update firewall.c * Update firewall.c * test * Update firewall.c * test * Update firewall.c * Update firewall.c * test * Update firewall.c * Update firewall.c * Update onvm_config_common.c * updates * Update firewall.c * Update firewall.c * Update rules.json * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * test * updates * updates * Update go.sh * Updates * Revert "Updates" This reverts commit 120b624b4f98156f160bfb2930f37a8913b76526. * Update firewall.c * updates * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * updates * Update onvm_config_common.c * Update onvm_config_common.c * Update firewall.c * Delete rules.json * Update firewall.c * Update firewall.c * Update firewall.c * Update README.md * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update onvm_nflib.c * Update onvm_nflib.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update firewall.c * Update onvm_nf.c * modifying go script, removing unnecessary code * Update firewall.c * Update firewall.c * Update firewall.c * Style fixes * more style fixes * More style fixes * Moving rules file, logic for if running from examples directory * Moving rules.json file * Delete rules.json from examples direc * Nuking custom go.sh script * Update README.md adding -f to the readme * Adding pkt total, drop, accepted stats * fixing readme * documentation and style fixes * bug fix: logic of dropping/accepting packets * bug fix: logic of dropping/accepting packets * style: change to 8 space indents * Multiple run support * style updates * added not ipv4 field * specify directory to rules.json file instead of specific name * IP's are now entered in proper format in rules.json * printing IP's in debug mode * Style fixes * Style fixes * Style fixes/double free/corruption error * Style fixes/double free/corruption error * style * Revert "style" This reverts commit b2753a6d7aa033860459c1c770ec4a6e87efc1d5. * Style fixes * Style fixes/whitespace * spacing fix * spacing fix * Space fix * Double free/corruption fix * Fixed depth issue * Style fixes * Read me updates * Parsing ip as cpu * Compatibility with onvm_pkt_parse_ip PR merge * Small fix in load_balancer * Remove unused fw accept tag * Creating function for char to ip * Adding a function to parse string to ip * Style nit * Style nit * Style nits and TODO * TODO * ip_disp to ip_string * Restoring lpm struct (accidentally deleted) * Restoring lpm status macro * Style fixes, naming, etc * Style fixes, naming * Style fixes * Style nit --- examples/Makefile | 2 +- examples/firewall/.gitignore | 2 + examples/firewall/Makefile | 62 +++++ examples/firewall/README.md | 31 +++ examples/firewall/firewall.c | 381 ++++++++++++++++++++++++++++++ examples/firewall/go.sh | 1 + examples/firewall/rules.json | 13 + onvm/onvm_mgr/onvm_nf.c | 33 +++ onvm/onvm_nflib/onvm_common.h | 11 +- onvm/onvm_nflib/onvm_msg_common.h | 1 + onvm/onvm_nflib/onvm_nflib.c | 26 ++ onvm/onvm_nflib/onvm_nflib.h | 11 + onvm/onvm_nflib/onvm_pkt_helper.c | 6 + onvm/onvm_nflib/onvm_pkt_helper.h | 6 + 14 files changed, 584 insertions(+), 2 deletions(-) create mode 100755 examples/firewall/.gitignore create mode 100755 examples/firewall/Makefile create mode 100755 examples/firewall/README.md create mode 100755 examples/firewall/firewall.c create mode 120000 examples/firewall/go.sh create mode 100755 examples/firewall/rules.json diff --git a/examples/Makefile b/examples/Makefile index 361bb596c..b3f0adb62 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -40,7 +40,7 @@ $(error "Please define RTE_SDK environment variable") endif # To add new examples, append the directory name to this variable -examples = bridge basic_monitor simple_forward speed_tester flow_table test_flow_dir aes_encrypt aes_decrypt flow_tracker load_balancer arp_response nf_router scaling_example load_generator payload_scan +examples = bridge basic_monitor simple_forward speed_tester flow_table test_flow_dir aes_encrypt aes_decrypt flow_tracker load_balancer arp_response nf_router scaling_example load_generator payload_scan firewall ifeq ($(NDPI_HOME),) $(warning "Skipping ndpi_stats NF as NDPI_HOME is not set") diff --git a/examples/firewall/.gitignore b/examples/firewall/.gitignore new file mode 100755 index 000000000..10388a2f8 --- /dev/null +++ b/examples/firewall/.gitignore @@ -0,0 +1,2 @@ +firewall/ +build/ diff --git a/examples/firewall/Makefile b/examples/firewall/Makefile new file mode 100755 index 000000000..02a6e4e28 --- /dev/null +++ b/examples/firewall/Makefile @@ -0,0 +1,62 @@ +# openNetVM +# https://github.com/sdnfv/openNetVM +# +# BSD LICENSE +# +# Copyright(c) +# 2015-2016 George Washington University +# 2015-2016 University of California Riverside +# 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. +# The name of the author may not 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. + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +RTE_TARGET ?= $(RTE_TARGET) + +# Default target, can be overriden by command line or environment +include $(RTE_SDK)/mk/rte.vars.mk + +# binary name +APP = firewall + +# all source are stored in SRCS-y +SRCS-y := firewall.c + +# OpenNetVM path +ONVM= $(SRCDIR)/../../onvm + +CFLAGS += -O3 $(USER_FLAGS) + +CFLAGS += -I$(ONVM)/onvm_nflib +CFLAGS += -I$(ONVM)/lib +LDFLAGS += $(ONVM)/onvm_nflib/$(RTE_TARGET)/libonvm.a +LDFLAGS += $(ONVM)/lib/$(RTE_TARGET)/lib/libonvmhelper.a -lm + +include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/firewall/README.md b/examples/firewall/README.md new file mode 100755 index 000000000..7e18d4a83 --- /dev/null +++ b/examples/firewall/README.md @@ -0,0 +1,31 @@ +Firewall +== +The Firewall NF drops/forwards packets based on LPM rules specified in the rules.json file. +A user would enter a rule in the following format: + +```` +"ruleName": { + "ip": "127.1.1.0", + "depth": 32, + "action": 0 + } +```` +Compilation and Execution +-- +``` +cd examples +make +cd firewall +./go.sh SERVICE_ID -d DESTINATION_ID -f RULES_FILE + +OR + +./go.sh -F CONFIG_FILE -- -- -d DST -f RULES_FILE [-p PRINT_DELAY] [-b debug mode] +``` + +App Specific Arguments +-- + - `-b`: specifies debug mode. Prints individual packet source ip addresses. + - `-f `: rules used for LPM lookup. + - `-p +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +#include +#include +#include +#include + +#include + +#include "onvm_nflib.h" +#include "onvm_pkt_helper.h" +#include "onvm_config_common.h" + +#define NF_TAG "firewall" + +#define MAX_RULES 256 +#define NUM_TBLS 8 + +static uint16_t destination; +static int debug = 0; +char *rule_file = NULL; + +/* Structs that contain information about this NF/set up LPM rules */ +struct onvm_nf_info *nf_info; +struct lpm_request *firewall_req; +static struct firewall_pkt_stats stats; +struct rte_lpm *lpm_tbl; +struct onvm_fw_rule **rules; + +/* Number of packets between each print */ +static uint32_t print_delay = 10000000; + +/* Shared data structure containing host port info */ +extern struct port_info *ports; + +/* Struct for the firewall LPM rules */ +struct onvm_fw_rule { + uint32_t src_ip; + uint8_t depth; + uint8_t action; +}; + +/* Struct for printing stats */ +struct firewall_pkt_stats { + uint64_t pkt_drop; + uint64_t pkt_accept; + uint64_t pkt_not_ipv4; + uint64_t pkt_total; +}; + +/* + * Print a usage message + */ +static void +usage(const char *progname) { + printf("Usage: %s [EAL args] -- [NF_LIB args] -- -p -f [-b]\n\n", progname); + printf("Flags:\n"); + printf(" - `-d DST`: Destination Service ID to forward to\n"); + printf(" - `-p PRINT_DELAY`: Number of packets between each print, e.g. `-p 1` prints every packets.\n"); + printf(" - `-b`: Debug mode: Print each incoming packets source/destination" + " IP address as well as its drop/forward status\n"); + printf(" - `-f`: Path to a JSON file containing firewall rules; See README for example usage\n"); +} + +/* + * Parse the application arguments. + */ +static int +parse_app_args(int argc, char *argv[], const char *progname) { + int c, dst_flag = 0, rules_init = 0; + + while ((c = getopt(argc, argv, "d:f:p:b")) != -1) { + switch (c) { + case 'd': + destination = strtoul(optarg, NULL, 10); + dst_flag = 1; + break; + case 'p': + print_delay = strtoul(optarg, NULL, 10); + RTE_LOG(INFO, APP, "Print delay = %d\n", print_delay); + break; + case 'f': + rule_file = strdup(optarg); + rules_init = 1; + break; + case 'b': + RTE_LOG(INFO, APP, "Debug mode enabled; printing the source IP addresses" + " of each incoming packet as well as drop/forward status\n"); + debug = 1; + break; + case '?': + usage(progname); + if (optopt == 'p') + RTE_LOG(INFO, APP, "Option -%c requires an argument.\n", optopt); + if (optopt == 'd') + RTE_LOG(INFO, APP, "Option -%c requires an argument.\n", optopt); + if (optopt == 'f') + RTE_LOG(INFO, APP, "Option -%c requires an argument.\n", optopt); + else if (isprint(optopt)) + RTE_LOG(INFO, APP, "Unknown option `-%c'.\n", optopt); + else + RTE_LOG(INFO, APP, "Unknown option character `\\x%x'.\n", optopt); + return -1; + default: + usage(progname); + return -1; + } + } + + if (!dst_flag) { + RTE_LOG(INFO, APP, "Firewall NF requires a destination NF with the -d flag.\n"); + return -1; + } + if (!debug) { + RTE_LOG(INFO, APP, "Running normal mode, use -b flag to enable debug mode\n"); + } + if (!rules_init) { + RTE_LOG(INFO, APP, "Please specify a rules JSON file with -f FILE_NAME\n"); + return -1; + } + return optind; +} + +/* + * This function displays stats. It uses ANSI terminal codes to clear + * screen when called. It is called from a single non-master + * thread in the server process, when the process is run with more + * than one lcore enabled. + */ +static void +do_stats_display(void) { + const char clr[] = {27, '[', '2', 'J', '\0'}; + const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'}; + + /* Clear screen and move to top left */ + printf("%s%s", clr, topLeft); + printf("Packets Dropped: %lu\n", stats.pkt_drop); + printf("Packets not IPv4: %lu\n", stats.pkt_not_ipv4); + printf("Packets Accepted: %lu\n", stats.pkt_accept); + printf("Packets Total: %lu", stats.pkt_total); + + printf("\n\n"); +} + +static int +packet_handler(struct rte_mbuf *pkt, struct onvm_pkt_meta *meta, __attribute__((unused)) struct onvm_nf_info *nf_info) { + struct ipv4_hdr *ipv4_hdr; + static uint32_t counter = 0; + int ret; + uint32_t rule = 0; + uint32_t track_ip = 0; + char ip_string[16]; + + if (++counter == print_delay) { + do_stats_display(); + counter = 0; + } + + stats.pkt_total++; + + if (!onvm_pkt_is_ipv4(pkt)) { + if (debug) RTE_LOG(INFO, APP, "Packet received not ipv4\n"); + stats.pkt_not_ipv4++; + meta->action = ONVM_NF_ACTION_DROP; + return 0; + } + + ipv4_hdr = onvm_pkt_ipv4_hdr(pkt); + ret = rte_lpm_lookup(lpm_tbl, rte_be_to_cpu_32(ipv4_hdr->src_addr), &rule); + + if (debug) onvm_pkt_parse_char_ip(ip_string, rte_be_to_cpu_32(ipv4_hdr->src_addr)); + + if (ret < 0) { + meta->action = ONVM_NF_ACTION_DROP; + stats.pkt_drop++; + if (debug) RTE_LOG(INFO, APP, "Packet from source IP %s has been dropped\n", ip_string); + return 0; + } + + switch (rule) { + case 0: + meta->action = ONVM_NF_ACTION_TONF; + meta->destination = destination; + stats.pkt_accept++; + if (debug) RTE_LOG(INFO, APP, "Packet from source IP %s has been accepted\n", ip_string); + break; + default: + meta->action = ONVM_NF_ACTION_DROP; + stats.pkt_drop++; + if (debug) RTE_LOG(INFO, APP, "Packet from source IP %s has been dropped\n", ip_string); + break; + } + + return 0; +} + +static int +lpm_setup(struct onvm_fw_rule **rules, int num_rules) { + int i, status, ret; + uint32_t ip; + char name[64]; + char ip_string[16]; + + firewall_req = (struct lpm_request *) rte_malloc(NULL, sizeof(struct lpm_request), 0); + + if (!firewall_req) return 0; + + snprintf(name, sizeof(name), "fw%d-%"PRIu64, rte_lcore_id(), rte_get_tsc_cycles()); + firewall_req->max_num_rules = 1024; + firewall_req->num_tbl8s = 24; + firewall_req->socket_id = rte_socket_id(); + snprintf(firewall_req->name, sizeof(name), "%s", name); + status = onvm_nflib_request_lpm(firewall_req); + + if (status < 0) { + rte_exit(EXIT_FAILURE, "Cannot get lpm region for firewall\n"); + } + + lpm_tbl = rte_lpm_find_existing(name); + + if (lpm_tbl == NULL) { + printf("No existing LPM_TBL\n"); + } + + for (i = 0; i < num_rules; ++i) { + ip = rules[i]->src_ip; + onvm_pkt_parse_char_ip(ip_string, ip); + printf("RULE %d: { ip: %s, depth: %d, action: %d }\n", i, ip_string, rules[i]->depth, rules[i]->action); + ret = rte_lpm_add(lpm_tbl, rules[i]->src_ip, rules[i]->depth, rules[i]->action); + if (ret < 0) { + printf("ERROR ADDING RULE %d\n", ret); + return 1; + } + } + rte_free(firewall_req); + + return 0; +} + +static void +lpm_teardown(struct onvm_fw_rule **rules, int num_rules) { + int i; + + if (rules) { + for (i = 0; i < num_rules; ++i) { + if (rules[i]) free(rules[i]); + } + free(rules); + } + + if (lpm_tbl) { + rte_lpm_free(lpm_tbl); + } + + if (rule_file) { + free(rule_file); + } +} + +struct onvm_fw_rule +**setup_rules(int *total_rules, char *rules_file) { + int ip[4]; + int num_rules, ret; + int i = 0; + + cJSON *rules_json = onvm_config_parse_file(rules_file); + cJSON *rules_ip = NULL; + cJSON *depth = NULL; + cJSON *action = NULL; + + if (rules_json == NULL) { + rte_exit(EXIT_FAILURE, "%s file could not be parsed/not found. Assure rules file" + " the directory to the rules file is being specified.\n", rules_file); + } + + num_rules = onvm_config_get_item_count(rules_json); + *total_rules = num_rules; + rules = (struct onvm_fw_rule **) malloc(num_rules * sizeof(struct onvm_fw_rule *)); + rules_json = rules_json->child; + + while (rules_json != NULL) { + rules_ip = cJSON_GetObjectItem(rules_json, "ip"); + depth = cJSON_GetObjectItem(rules_json, "depth"); + action = cJSON_GetObjectItem(rules_json, "action"); + + if (rules_ip == NULL) rte_exit(EXIT_FAILURE, "IP not found/invalid\n"); + if (depth == NULL) rte_exit(EXIT_FAILURE, "Depth not found/invalid\n"); + if (action == NULL) rte_exit(EXIT_FAILURE, "Action not found/invalid\n"); + + rules[i] = (struct onvm_fw_rule *) malloc(sizeof(struct onvm_fw_rule)); + onvm_pkt_parse_ip(rules_ip->valuestring, &rules[i]->src_ip); + rules[i]->depth = depth->valueint; + rules[i]->action = action->valueint; + rules_json = rules_json->next; + i++; + } + cJSON_Delete(rules_json); + + return rules; +} + +int main(int argc, char *argv[]) { + int arg_offset, num_rules; + struct onvm_fw_rule **rules; + + stats.pkt_drop = 0; + stats.pkt_accept = 0; + + const char *progname = argv[0]; + + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG, &nf_info)) < 0) + return -1; + argc -= arg_offset; + argv += arg_offset; + + if (parse_app_args(argc, argv, progname) < 0) { + onvm_nflib_stop(nf_info); + rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); + } + + rules = setup_rules(&num_rules, rule_file); + lpm_setup(rules, num_rules); + onvm_nflib_run(nf_info, &packet_handler); + + lpm_teardown(rules, num_rules); + printf("If we reach here, program is ending\n"); + return 0; +} diff --git a/examples/firewall/go.sh b/examples/firewall/go.sh new file mode 120000 index 000000000..40babd806 --- /dev/null +++ b/examples/firewall/go.sh @@ -0,0 +1 @@ +../go.sh \ No newline at end of file diff --git a/examples/firewall/rules.json b/examples/firewall/rules.json new file mode 100755 index 000000000..0a48150f2 --- /dev/null +++ b/examples/firewall/rules.json @@ -0,0 +1,13 @@ +{ + "rule1": { + "ip": "10.11.1.15", + "depth": 32, + "action": 0 + }, + + "rule2": { + "ip": "10.11.1.16", + "depth": 32, + "action": 0 + } +} \ No newline at end of file diff --git a/onvm/onvm_mgr/onvm_nf.c b/onvm/onvm_mgr/onvm_nf.c index 277010ab9..3f7da1dd3 100644 --- a/onvm/onvm_mgr/onvm_nf.c +++ b/onvm/onvm_mgr/onvm_nf.c @@ -49,6 +49,7 @@ #include "onvm_nf.h" #include "onvm_mgr.h" #include "onvm_stats.h" +#include /* ID 0 is reserved */ uint16_t next_instance_id = 1; @@ -86,6 +87,16 @@ onvm_nf_ready(struct onvm_nf_info *nf_info); inline static int onvm_nf_stop(struct onvm_nf_info *nf_info); +/* + * Function that initializes an LPM object + * + * Input : the address of an lpm_request struct + * Output : a return code based on initialization of the LPM object + * + */ +static void +onvm_nf_init_lpm_region(struct lpm_request *req_lpm); + /********************************Interfaces***********************************/ uint16_t @@ -128,6 +139,7 @@ onvm_nf_check_status(void) { void *msgs[MAX_NFS]; struct onvm_nf_msg *msg; struct onvm_nf_info *nf; + struct lpm_request *req_lpm; int num_msgs = rte_ring_count(incoming_msg_queue); uint16_t stop_nf_id; @@ -141,6 +153,11 @@ onvm_nf_check_status(void) { msg = (struct onvm_nf_msg *)msgs[i]; switch (msg->msg_type) { + case MSG_REQUEST_LPM_REGION: + // TODO: Add stats event handler here + req_lpm = (struct lpm_request *)msg->msg_data; + onvm_nf_init_lpm_region(req_lpm); + break; case MSG_NF_STARTING: nf = (struct onvm_nf_info *)msg->msg_data; if (onvm_nf_start(nf) == 0) { @@ -352,3 +369,19 @@ onvm_nf_stop(struct onvm_nf_info *nf_info) { return 0; } + +static void +onvm_nf_init_lpm_region(struct lpm_request *req_lpm) { + struct rte_lpm_config conf; + struct rte_lpm* lpm_region; + + conf.max_rules = req_lpm->max_num_rules; + conf.number_tbl8s = req_lpm->num_tbl8s; + + lpm_region = rte_lpm_create(req_lpm->name, req_lpm->socket_id, &conf); + if (lpm_region) { + req_lpm->status = 0; + } else { + req_lpm->status = -1; + } +} diff --git a/onvm/onvm_nflib/onvm_common.h b/onvm/onvm_nflib/onvm_common.h index 082420729..871ef5a35 100644 --- a/onvm/onvm_nflib/onvm_common.h +++ b/onvm/onvm_nflib/onvm_common.h @@ -63,7 +63,7 @@ #define ONVM_NF_ACTION_DROP 0 // drop packet #define ONVM_NF_ACTION_NEXT 1 // to whatever the next action is configured by the SDN controller in the flow table #define ONVM_NF_ACTION_TONF 2 // send to the NF specified in the argument field (assume it is on the same host) -#define ONVM_NF_ACTION_OUT 3 // send the packet out the NIC port set in the argument field +#define ONVM_NF_ACTION_OUT 3 // send the packet out the NIC port set in the argument field /* Used in setting bit flags for core options */ #define MANUAL_CORE_ASSIGNMENT_BIT 0 @@ -280,6 +280,14 @@ struct onvm_service_chain { int ref_cnt; }; +struct lpm_request { + char name[64]; + uint32_t max_num_rules; + uint32_t num_tbl8s; + int socket_id; + int status; +}; + /* define common names for structures shared between server and NF */ #define MP_NF_RXQ_NAME "MProc_Client_%u_RX" #define MP_NF_TXQ_NAME "MProc_Client_%u_TX" @@ -311,6 +319,7 @@ struct onvm_service_chain { #define NF_NO_DEDICATED_CORES 10 // There is no space for a dedicated core #define NF_CORE_OUT_OF_RANGE 11 // The manually selected core is out of range #define NF_CORE_BUSY 12 // The manually selected core is busy +#define NF_WAITING_FOR_LPM 13 // NF is waiting for a LPM request to be fulfilled #define NF_NO_ID -1 #define ONVM_NF_HANDLE_TX 1 // should be true if NFs primarily pass packets to each other diff --git a/onvm/onvm_nflib/onvm_msg_common.h b/onvm/onvm_nflib/onvm_msg_common.h index 301b5b553..266283ac5 100644 --- a/onvm/onvm_nflib/onvm_msg_common.h +++ b/onvm/onvm_nflib/onvm_msg_common.h @@ -52,6 +52,7 @@ #define MSG_NF_READY 4 #define MSG_SCALE 5 #define MSG_FROM_NF 6 +#define MSG_REQUEST_LPM_REGION 7 struct onvm_nf_msg { uint8_t msg_type; /* Constant saying what type of message is */ diff --git a/onvm/onvm_nflib/onvm_nflib.c b/onvm/onvm_nflib/onvm_nflib.c index f9e5c373b..7a36d7901 100644 --- a/onvm/onvm_nflib/onvm_nflib.c +++ b/onvm/onvm_nflib/onvm_nflib.c @@ -292,6 +292,32 @@ onvm_nflib_lookup_shared_structs(void) { return 0; } +int +onvm_nflib_request_lpm(struct lpm_request *lpm_req) { + struct onvm_nf_msg *request_message; + int ret; + + ret = rte_mempool_get(nf_msg_pool, (void **) (&request_message)); + if (ret != 0) return ret; + + request_message->msg_type = MSG_REQUEST_LPM_REGION; + request_message->msg_data = lpm_req; + + ret = rte_ring_enqueue(mgr_msg_queue, request_message); + if (ret < 0) { + rte_mempool_put(nf_msg_pool, request_message); + return ret; + } + + lpm_req->status = NF_WAITING_FOR_LPM; + for (; lpm_req->status == (uint16_t) NF_WAITING_FOR_LPM;) { + sleep(1); + } + + rte_mempool_put(nf_msg_pool, request_message); + return lpm_req->status; +} + static int onvm_nflib_start_nf(struct onvm_nf_info *nf_info) { struct onvm_nf_msg *startup_msg; diff --git a/onvm/onvm_nflib/onvm_nflib.h b/onvm/onvm_nflib/onvm_nflib.h index 2d224dafd..f756fc664 100644 --- a/onvm/onvm_nflib/onvm_nflib.h +++ b/onvm/onvm_nflib/onvm_nflib.h @@ -269,6 +269,17 @@ onvm_nflib_inherit_parent_config(struct onvm_nf_info *parent_info, void *data); int onvm_nflib_scale(struct onvm_nf_scale_info *scale_info); +/** + * Request LPM memory region. Returns the success or failure of this initialization. + * + * @param lpm_request + * An LPM request struct to initialize the LPM region + * @return + * Request response status + */ +int +onvm_nflib_request_lpm(struct lpm_request *req); + struct onvm_service_chain * onvm_nflib_get_default_chain(void); diff --git a/onvm/onvm_nflib/onvm_pkt_helper.c b/onvm/onvm_nflib/onvm_pkt_helper.c index 024f59786..5ed2e52fe 100644 --- a/onvm/onvm_nflib/onvm_pkt_helper.c +++ b/onvm/onvm_nflib/onvm_pkt_helper.c @@ -373,6 +373,12 @@ onvm_pkt_parse_ip(char* ip_str, uint32_t* dest) { return 0; } +void +onvm_pkt_parse_char_ip(char* ip_dest, uint32_t ip_src) { + snprintf(ip_dest, 16, "%u.%u.%u.%u", (ip_src >> 24) & 0xFF, (ip_src >> 16) & 0xFF, + (ip_src >> 8) & 0xFF, ip_src & 0xFF); +} + int onvm_pkt_parse_mac(char* mac_str, uint8_t* dest) { int ret, i; diff --git a/onvm/onvm_nflib/onvm_pkt_helper.h b/onvm/onvm_nflib/onvm_pkt_helper.h index 30dc3a425..e70b85287 100644 --- a/onvm/onvm_nflib/onvm_pkt_helper.h +++ b/onvm/onvm_nflib/onvm_pkt_helper.h @@ -140,6 +140,12 @@ onvm_pkt_print_ether(struct ether_hdr* hdr); int onvm_pkt_parse_ip(char* ip_str, uint32_t* dest); +/** + * Parse uint32 IP into a string + */ +void +onvm_pkt_parse_char_ip(char* ip_dest, uint32_t ip_src); + /** * Parsing mac addr of form xx:xx:xx:xx:xx:xx into dest array */