From 75693ea4d2c7ebc3369b5e81eb2a8a6dd4d228ea Mon Sep 17 00:00:00 2001 From: Adam Shimi Date: Fri, 26 Aug 2016 00:08:37 -0400 Subject: [PATCH] Refactored, cleaned up, and changed API (147) Refactoring to improve code organization A big set of commits to clean the structure and simplify onvm source code. We separated all functions into the main.c of the manager into modules : - `onvm_stats` : functions displaying statistics - `onvm_pkt` : functions related to packet processing - `onvm_nf` : functions related to NFs management. Each module comes with a header file with commented prototypes. And each c and h file has been "cut" into parts : - interfaces, or functions called outside of the module - internal functions, the functions called only inside the module and doing all the work - helper functions, simple and short functions used many times through the module. **API Changes:** - NFs now need to call functions like `onvm_nflib_*` instead of `onvm_nf_*`. For example, `onvm_nflib_init` instead of `onvm_nf_init`. The example NFs have all been updated accordingly. - NF `Makefiles` need to be updated to find the path to `onvm_nflib`. --- docs/Releases.md | 21 + examples/basic_monitor/Makefile | 4 +- examples/basic_monitor/monitor.c | 4 +- examples/bridge/Makefile | 4 +- examples/bridge/bridge.c | 4 +- examples/flow_table/Makefile | 4 +- examples/flow_table/flow_table.c | 4 +- examples/flow_table/sdn_pkt_list.h | 2 +- examples/simple_forward/Makefile | 4 +- examples/simple_forward/forward.c | 4 +- examples/speed_tester/Makefile | 4 +- examples/speed_tester/speed_tester.c | 6 +- examples/test_flow_dir/Makefile | 4 +- examples/test_flow_dir/test_flow_dir.c | 4 +- onvm/Makefile | 2 +- onvm/onvm_mgr/Makefile | 4 +- onvm/onvm_mgr/main.c | 669 ++-------------------- onvm/onvm_mgr/{args.c => onvm_args.c} | 205 ++++--- onvm/onvm_mgr/{args.h => onvm_args.h} | 23 +- onvm/onvm_mgr/{init.c => onvm_init.c} | 287 ++++------ onvm/onvm_mgr/{init.h => onvm_init.h} | 96 +++- onvm/onvm_mgr/onvm_mgr.h | 129 +++++ onvm/onvm_mgr/onvm_nf.c | 240 ++++++++ onvm/onvm_mgr/onvm_nf.h | 102 ++++ onvm/onvm_mgr/onvm_pkt.c | 396 +++++++++++++ onvm/onvm_mgr/onvm_pkt.h | 116 ++++ onvm/onvm_mgr/onvm_stats.c | 219 +++++++ onvm/onvm_mgr/onvm_stats.h | 89 +++ onvm/{onvm_nf => onvm_nflib}/Makefile | 0 onvm/{onvm_nf => onvm_nflib}/onvm_nflib.c | 346 ++++++----- onvm/{onvm_nf => onvm_nflib}/onvm_nflib.h | 52 +- onvm/onvm_nflib/onvm_nflib_internal.h | 162 ++++++ onvm/shared/onvm_includes.h | 101 ++++ 33 files changed, 2221 insertions(+), 1090 deletions(-) create mode 100644 docs/Releases.md rename onvm/onvm_mgr/{args.c => onvm_args.c} (87%) rename onvm/onvm_mgr/{args.h => onvm_args.h} (82%) rename onvm/onvm_mgr/{init.c => onvm_init.c} (87%) rename onvm/onvm_mgr/{init.h => onvm_init.h} (69%) create mode 100644 onvm/onvm_mgr/onvm_mgr.h create mode 100644 onvm/onvm_mgr/onvm_nf.c create mode 100644 onvm/onvm_mgr/onvm_nf.h create mode 100644 onvm/onvm_mgr/onvm_pkt.c create mode 100644 onvm/onvm_mgr/onvm_pkt.h create mode 100644 onvm/onvm_mgr/onvm_stats.c create mode 100644 onvm/onvm_mgr/onvm_stats.h rename onvm/{onvm_nf => onvm_nflib}/Makefile (100%) rename onvm/{onvm_nf => onvm_nflib}/onvm_nflib.c (80%) rename onvm/{onvm_nf => onvm_nflib}/onvm_nflib.h (83%) create mode 100644 onvm/onvm_nflib/onvm_nflib_internal.h create mode 100644 onvm/shared/onvm_includes.h diff --git a/docs/Releases.md b/docs/Releases.md new file mode 100644 index 000000000..0423deab2 --- /dev/null +++ b/docs/Releases.md @@ -0,0 +1,21 @@ +## Release Notes + +#### 8/25/16: Refactoring to improve code organization +A big set of commits to clean the structure and simplify onvm source code. +We separated all functions into the main.c of the manager into modules : + - `onvm_stats` : functions displaying statistics + - `onvm_pkt` : functions related to packet processing + - `onvm_nf` : functions related to NFs management. + +Each module comes with a header file with commented prototypes. And each c and h file has been "cut" into parts : + - interfaces, or functions called outside of the module + - internal functions, the functions called only inside the module and doing all the work + - helper functions, simple and short functions used many times through the module. + +**API Changes:** + - NFs now need to call functions like `onvm_nflib_*` instead of `onvm_nf_*`. For example, `onvm_nflib_init` instead of `onvm_nf_init`. The example NFs have all been updated accordingly. + - NF `Makefiles` need to be updated to find the path to `onvm_nflib`. + + +#### 4/24/16: Initial Release +Initial source code release. diff --git a/examples/basic_monitor/Makefile b/examples/basic_monitor/Makefile index 5a5e4088d..1efc5f4f5 100644 --- a/examples/basic_monitor/Makefile +++ b/examples/basic_monitor/Makefile @@ -54,9 +54,9 @@ ONVM= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/$(RTE_TARGET)/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/$(RTE_TARGET)/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_sc_common.o diff --git a/examples/basic_monitor/monitor.c b/examples/basic_monitor/monitor.c index 5217b1030..e0a17550f 100644 --- a/examples/basic_monitor/monitor.c +++ b/examples/basic_monitor/monitor.c @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; - if ((arg_offset = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= arg_offset; argv += arg_offset; @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) { if (parse_app_args(argc, argv, progname) < 0) rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("If we reach here, program is ending"); return 0; } diff --git a/examples/bridge/Makefile b/examples/bridge/Makefile index ffc979425..1357b688c 100644 --- a/examples/bridge/Makefile +++ b/examples/bridge/Makefile @@ -53,9 +53,9 @@ ONVM= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/$(RTE_TARGET)/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/$(RTE_TARGET)/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_sc_common.o diff --git a/examples/bridge/bridge.c b/examples/bridge/bridge.c index f710a5235..5c95df7be 100644 --- a/examples/bridge/bridge.c +++ b/examples/bridge/bridge.c @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; - if ((arg_offset = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= arg_offset; argv += arg_offset; @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) { if (parse_app_args(argc, argv, progname) < 0) rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("If we reach here, program is ending"); return 0; } diff --git a/examples/flow_table/Makefile b/examples/flow_table/Makefile index 3ef0ef3a8..e1115b109 100644 --- a/examples/flow_table/Makefile +++ b/examples/flow_table/Makefile @@ -54,9 +54,9 @@ ONVM ?= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/x86_64-native-linuxapp-gcc/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/x86_64-native-linuxapp-gcc/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_sc_common.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_flow_table.o diff --git a/examples/flow_table/flow_table.c b/examples/flow_table/flow_table.c index 6d9c0e790..11294a3cf 100644 --- a/examples/flow_table/flow_table.c +++ b/examples/flow_table/flow_table.c @@ -248,7 +248,7 @@ int main(int argc, char *argv[]) { int retval; unsigned sdn_core = 0; - if ((retval = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((retval = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= retval; argv += retval; @@ -271,7 +271,7 @@ int main(int argc, char *argv[]) { /* Map sdn_ft table */ onvm_flow_dir_nf_init(); printf("Starting packet handler.\n"); - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("NF exiting..."); cleanup(); return 0; diff --git a/examples/flow_table/sdn_pkt_list.h b/examples/flow_table/sdn_pkt_list.h index e47b86509..20b316590 100644 --- a/examples/flow_table/sdn_pkt_list.h +++ b/examples/flow_table/sdn_pkt_list.h @@ -110,7 +110,7 @@ sdn_pkt_list_flush(struct sdn_pkt_list* list) { meta = onvm_get_pkt_meta(pkt); meta->action = ONVM_NF_ACTION_NEXT; meta->chain_index = 0; - onvm_nf_return_pkt(pkt); + onvm_nflib_return_pkt(pkt); free(entry); list->counter--; } diff --git a/examples/simple_forward/Makefile b/examples/simple_forward/Makefile index 7aad4a6d3..91ecabeae 100644 --- a/examples/simple_forward/Makefile +++ b/examples/simple_forward/Makefile @@ -54,9 +54,9 @@ ONVM= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/x86_64-native-linuxapp-gcc/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/x86_64-native-linuxapp-gcc/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_sc_common.o diff --git a/examples/simple_forward/forward.c b/examples/simple_forward/forward.c index 2fc2457ff..6cb5a6ee9 100644 --- a/examples/simple_forward/forward.c +++ b/examples/simple_forward/forward.c @@ -168,7 +168,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; - if ((arg_offset = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= arg_offset; argv += arg_offset; @@ -176,7 +176,7 @@ int main(int argc, char *argv[]) { if (parse_app_args(argc, argv, progname) < 0) rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("If we reach here, program is ending"); return 0; } diff --git a/examples/speed_tester/Makefile b/examples/speed_tester/Makefile index 71512ab11..913e4eb29 100644 --- a/examples/speed_tester/Makefile +++ b/examples/speed_tester/Makefile @@ -54,9 +54,9 @@ ONVM ?= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/$(RTE_TARGET)/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/$(RTE_TARGET)/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/$(RTE_TARGET)/onvm_sc_common.o diff --git a/examples/speed_tester/speed_tester.c b/examples/speed_tester/speed_tester.c index 4ab107b17..6c84e5b75 100644 --- a/examples/speed_tester/speed_tester.c +++ b/examples/speed_tester/speed_tester.c @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; - if ((arg_offset = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= arg_offset; argv += arg_offset; @@ -204,10 +204,10 @@ int main(int argc, char *argv[]) { pmeta->action = ONVM_NF_ACTION_TONF; pkts[i]->port = 3; pkts[i]->hash.rss = i; - onvm_nf_return_pkt(pkts[i]); + onvm_nflib_return_pkt(pkts[i]); } - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("If we reach here, program is ending"); return 0; } diff --git a/examples/test_flow_dir/Makefile b/examples/test_flow_dir/Makefile index 7f37324ce..a96e0f722 100644 --- a/examples/test_flow_dir/Makefile +++ b/examples/test_flow_dir/Makefile @@ -54,10 +54,10 @@ ONVM= $(SRCDIR)/../../onvm CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) -CFLAGS += -I$(ONVM)/onvm_nf +CFLAGS += -I$(ONVM)/onvm_nflib CFLAGS += -I$(ONVM)/onvm_mgr CFLAGS += -I$(ONVM)/shared -LDFLAGS += $(ONVM)/onvm_nf/onvm_nf/x86_64-native-linuxapp-gcc/onvm_nflib.o +LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/x86_64-native-linuxapp-gcc/onvm_nflib.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_pkt_helper.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_sc_common.o LDFLAGS += $(ONVM)/shared/shared/x86_64-native-linuxapp-gcc/onvm_sc_mgr.o diff --git a/examples/test_flow_dir/test_flow_dir.c b/examples/test_flow_dir/test_flow_dir.c index e35efc190..68e853ed4 100644 --- a/examples/test_flow_dir/test_flow_dir.c +++ b/examples/test_flow_dir/test_flow_dir.c @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) { const char *progname = argv[0]; - if ((arg_offset = onvm_nf_init(argc, argv, NF_TAG)) < 0) + if ((arg_offset = onvm_nflib_init(argc, argv, NF_TAG)) < 0) return -1; argc -= arg_offset; argv += arg_offset; @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { /* Map the sdn_ft table */ onvm_flow_dir_nf_init(); - onvm_nf_run(nf_info, &packet_handler); + onvm_nflib_run(nf_info, &packet_handler); printf("If we reach here, program is ending"); return 0; diff --git a/onvm/Makefile b/onvm/Makefile index e652b2159..84c86c1d0 100644 --- a/onvm/Makefile +++ b/onvm/Makefile @@ -47,6 +47,6 @@ include $(RTE_SDK)/mk/rte.vars.mk DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += shared DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += onvm_mgr -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += onvm_nf +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += onvm_nflib include $(RTE_SDK)/mk/rte.extsubdir.mk diff --git a/onvm/onvm_mgr/Makefile b/onvm/onvm_mgr/Makefile index 27e44c738..aa589bba7 100644 --- a/onvm/onvm_mgr/Makefile +++ b/onvm/onvm_mgr/Makefile @@ -53,9 +53,9 @@ endif APP = onvm_mgr # all source are stored in SRCS-y -SRCS-y := main.c init.c args.c +SRCS-y := main.c onvm_init.c onvm_args.c onvm_stats.c onvm_pkt.c onvm_nf.c -INC := $(wildcard *.h) +INC := onvm_mgr.h onvm_init.h onvm_args.h onvm_stats.h onvm_nf.h onvm_pkt.h CFLAGS += $(WERROR_FLAGS) -O3 $(USER_FLAGS) CFLAGS += -I$(SRCDIR)/../ diff --git a/onvm/onvm_mgr/main.c b/onvm/onvm_mgr/main.c index 89fedb832..a353b7f44 100644 --- a/onvm/onvm_mgr/main.c +++ b/onvm/onvm_mgr/main.c @@ -36,346 +36,26 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * main.c - simple onvm host code ********************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "shared/common.h" -#include "onvm_mgr/args.h" -#include "onvm_mgr/init.h" -#include "shared/onvm_sc_mgr.h" -#include "shared/onvm_flow_table.h" -#include "shared/onvm_flow_dir.h" -/* - * When doing reads from the NIC or the client queues, - * use this batch size - */ -#define PACKET_READ_SIZE ((uint16_t)32) +/****************************************************************************** + main.c -#define TO_PORT 0 -#define TO_CLIENT 1 + File containing the main function of the manager and all its worker + threads. -/* - * Local buffers to put packets in, used to send packets in bursts to the - * clients or to the NIC - */ -struct packet_buf { - struct rte_mbuf *buffer[PACKET_READ_SIZE]; - uint16_t count; -}; +******************************************************************************/ -/* ID to be assigned to the next NF that starts */ -static uint16_t next_instance_id; -/** Thread state. This specifies which NFs the thread will handle and - * includes the packet buffers used by the thread for NFs and ports. - */ -struct thread_info { - unsigned queue_id; - unsigned first_cl; - unsigned last_cl; - /* FIXME: This is confusing since it is non-inclusive. It would be - * better to have this take the first client and the number - * of consecutive clients after it to handle. - */ - struct packet_buf *nf_rx_buf; - struct packet_buf *port_tx_buf; -}; - - -/** - Helper function that drop a packet and uses the success return convention - (a 0). - */ -static int -drop_packet(struct rte_mbuf *pkt) { - rte_pktmbuf_free(pkt); - if (pkt != NULL) { - return 1; - } - return 0; -} +#include "onvm_mgr.h" +#include "onvm_stats.h" +#include "onvm_pkt.h" +#include "onvm_nf.h" -static const char * -get_printable_mac_addr(uint8_t port) { - static const char err_address[] = "00:00:00:00:00:00"; - static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)]; - - if (unlikely(port >= RTE_MAX_ETHPORTS)) - return err_address; - if (unlikely(addresses[port][0] == '\0')) { - struct ether_addr mac; - rte_eth_macaddr_get(port, &mac); - snprintf(addresses[port], sizeof(addresses[port]), - "%02x:%02x:%02x:%02x:%02x:%02x\n", - mac.addr_bytes[0], mac.addr_bytes[1], mac.addr_bytes[2], - mac.addr_bytes[3], mac.addr_bytes[4], mac.addr_bytes[5]); - } - return addresses[port]; -} -/** - * Helper function to determine if an item in the clients array represents a valid NF - * A "valid" NF consists of: - * - A non-null index that also contains an associated info struct - * - A status set to NF_RUNNING - */ -static inline int -is_valid_nf(struct client *cl) -{ - return cl && cl->info && cl->info->status == NF_RUNNING; -} +/*******************************Worker threads********************************/ -/* - * This function displays the recorded statistics for each port - * and for each client. 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(unsigned sleeptime) { - unsigned i; - /* Arrays to store last TX/RX count to calculate rate */ - static uint64_t tx_last[RTE_MAX_ETHPORTS]; - static uint64_t rx_last[RTE_MAX_ETHPORTS]; - 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("PORTS\n"); - printf("-----\n"); - for (i = 0; i < ports->num_ports; i++) - printf("Port %u: '%s'\t", (unsigned)ports->id[i], - get_printable_mac_addr(ports->id[i])); - printf("\n\n"); - for (i = 0; i < ports->num_ports; i++) { - printf("Port %u - rx: %9"PRIu64" (%9"PRIu64" pps)\t" - "tx: %9"PRIu64" (%9"PRIu64" pps)\n", - (unsigned)ports->id[i], - ports->rx_stats.rx[ports->id[i]], - (ports->rx_stats.rx[ports->id[i]] - rx_last[i])/sleeptime, - ports->tx_stats.tx[ports->id[i]], - (ports->tx_stats.tx[ports->id[i]] - tx_last[i])/sleeptime); - rx_last[i] = ports->rx_stats.rx[ports->id[i]]; - tx_last[i] = ports->tx_stats.tx[ports->id[i]]; - } - - printf("\nCLIENTS\n"); - printf("-------\n"); - for (i = 0; i < MAX_CLIENTS; i++) { - if (!is_valid_nf(&clients[i])) - continue; - const uint64_t rx = clients[i].stats.rx; - const uint64_t rx_drop = clients[i].stats.rx_drop; - const uint64_t tx = clients_stats->tx[i]; - const uint64_t tx_drop = clients_stats->tx_drop[i]; - const uint64_t act_drop = clients[i].stats.act_drop; - const uint64_t act_next = clients[i].stats.act_next; - const uint64_t act_out = clients[i].stats.act_out; - const uint64_t act_tonf = clients[i].stats.act_tonf; - const uint64_t act_buffer = clients_stats->tx_buffer[i]; - const uint64_t act_returned = clients_stats->tx_returned[i]; - - printf("Client %2u - rx: %9"PRIu64" rx_drop: %9"PRIu64" next: %9"PRIu64" drop: %9"PRIu64" ret: %9"PRIu64"\n" - " tx: %9"PRIu64" tx_drop: %9"PRIu64" out: %9"PRIu64" tonf: %9"PRIu64" buf: %9"PRIu64" \n", - clients[i].info->instance_id, rx, rx_drop, act_next, act_drop, act_returned, tx, tx_drop, act_out, act_tonf, act_buffer); - } - - printf("\n"); -} - -/** - * Verifies that the next client id the manager gives out is unused - * This lets us account for the case where an NF has a manually specified id and we overwrite it - * This function modifies next_instance_id to be the proper value - */ -static int -find_next_instance_id(void) { - struct client *cl; - while (next_instance_id < MAX_CLIENTS) { - cl = &clients[next_instance_id]; - if (!is_valid_nf(cl)) - break; - next_instance_id++; - } - return next_instance_id; - -} - -/** - * Set up a newly started NF - * Assign it an ID (if it hasn't self-declared) - * Store info struct in our internal list of clients - * Returns 1 (TRUE) on successful start, 0 if there is an error (ID conflict) - */ -static inline int -start_new_nf(struct onvm_nf_info *nf_info) -{ - //TODO dynamically allocate memory here - make rx/tx ring - // take code from init_shm_rings in init.c - // flush rx/tx queue at the this index to start clean? - - // if NF passed its own id on the command line, don't assign here - // assume user is smart enough to avoid duplicates - uint16_t nf_id = nf_info->instance_id == (uint16_t)NF_NO_ID - ? next_instance_id++ - : nf_info->instance_id; - - if (nf_id >= MAX_CLIENTS) { - // There are no more available IDs for this NF - nf_info->status = NF_NO_IDS; - return 0; - } - - if (is_valid_nf(&clients[nf_id])) { - // This NF is trying to declare an ID already in use - nf_info->status = NF_ID_CONFLICT; - return 0; - } - - // Keep reference to this NF in the manager - nf_info->instance_id = nf_id; - clients[nf_id].info = nf_info; - clients[nf_id].instance_id = nf_id; - - // Register this NF running within its service - uint16_t service_count = nf_per_service_count[nf_info->service_id]++; - service_to_nf[nf_info->service_id][service_count] = nf_id; - - // Let the NF continue its init process - nf_info->status = NF_STARTING; - return 1; -} - -/** - * Clean up after an NF has stopped - * Remove references to soon-to-be-freed info struct - * Clean up stats values - */ -static inline void -stop_running_nf(struct onvm_nf_info *nf_info) -{ - uint16_t nf_id = nf_info->instance_id; - uint16_t service_id = nf_info->service_id; - int mapIndex; - struct rte_mempool *nf_info_mp; - - /* Clean up dangling pointers to info struct */ - clients[nf_id].info = NULL; - - /* Reset stats */ - clients[nf_id].stats.rx = clients[nf_id].stats.rx_drop = 0; - clients[nf_id].stats.act_drop = clients[nf_id].stats.act_tonf = 0; - clients[nf_id].stats.act_next = clients[nf_id].stats.act_out = 0; - - /* Remove this NF from the service map. - * Need to shift all elements past it in the array left to avoid gaps */ - nf_per_service_count[service_id]--; - for(mapIndex = 0; mapIndex < MAX_CLIENTS_PER_SERVICE; mapIndex++) { - if (service_to_nf[service_id][mapIndex] == nf_id) { - break; - } - } - - if (mapIndex < MAX_CLIENTS_PER_SERVICE) { // sanity error check - service_to_nf[service_id][mapIndex] = 0; - for (; mapIndex < MAX_CLIENTS_PER_SERVICE - 1; mapIndex++) { - // Shift the NULL to the end of the array - if (service_to_nf[service_id][mapIndex + 1] == 0) { - // Short circuit when we reach the end of this service's list - break; - } - service_to_nf[service_id][mapIndex] = service_to_nf[service_id][mapIndex + 1]; - service_to_nf[service_id][mapIndex + 1] = 0; - } - } - - /* Free info struct */ - /* Lookup mempool for nf_info struct */ - nf_info_mp = rte_mempool_lookup(_NF_MEMPOOL_NAME); - if (nf_info_mp == NULL) - return; - - rte_mempool_put(nf_info_mp, (void*)nf_info); -} - -static void -do_check_new_nf_status(void) { - int i; - int added_clients; - int removed_clients; - void *new_nfs[MAX_CLIENTS]; - struct onvm_nf_info *nf; - int num_new_nfs = rte_ring_count(nf_info_queue); - int dequeue_val = rte_ring_dequeue_bulk(nf_info_queue, new_nfs, num_new_nfs); - - if (dequeue_val != 0) - return; - - added_clients = 0; - removed_clients = 0; - for (i = 0; i < num_new_nfs; i++) { - nf = (struct onvm_nf_info *)new_nfs[i]; - - // Sets next_instance_id variable to next available - find_next_instance_id(); - - if (nf->status == NF_WAITING_FOR_ID) { - /* We're starting up a new NF. - * Function returns TRUE on successful start */ - if (start_new_nf(nf)) - added_clients++; - } else if (nf->status == NF_STOPPED) { - /* An existing NF is stopping */ - stop_running_nf(nf); - removed_clients++; - } - } - - num_clients += added_clients; - num_clients -= removed_clients; -} /* * Stats thread periodically prints per-port and per-NF stats. @@ -391,255 +71,11 @@ master_thread_main(void) { /* Loop forever: sleep always returns 0 or <= param */ while (sleep(sleeptime) <= sleeptime) { - do_check_new_nf_status(); - do_stats_display(sleeptime); + onvm_nf_check_status(); + onvm_stats_display_all(sleeptime); } } -/* - * Function to set all the client statistic values to zero. - */ -static void -clear_stats(void) { - unsigned i; - - for (i = 0; i < MAX_CLIENTS; i++) { - clients[i].stats.rx = clients[i].stats.rx_drop = 0; - clients[i].stats.act_drop = clients[i].stats.act_tonf = 0; - clients[i].stats.act_next = clients[i].stats.act_out = 0; - } -} - -/* - * Send a burst of traffic to a client, assuming there are packets - * available to be sent to this client - */ -static void -flush_nf_queue(struct thread_info *thread, uint16_t client) { - uint16_t i; - struct client *cl; - - if (thread->nf_rx_buf[client].count == 0) - return; - - cl = &clients[client]; - - // Ensure destination NF is running and ready to receive packets - if (!is_valid_nf(cl)) - return; - - if (rte_ring_enqueue_bulk(cl->rx_q, (void **)thread->nf_rx_buf[client].buffer, - thread->nf_rx_buf[client].count) != 0) { - for (i = 0; i < thread->nf_rx_buf[client].count; i++) { - drop_packet(thread->nf_rx_buf[client].buffer[i]); - } - cl->stats.rx_drop += thread->nf_rx_buf[client].count; - } else { - cl->stats.rx += thread->nf_rx_buf[client].count; - } - thread->nf_rx_buf[client].count = 0; -} - -/** - * Send a burst of packets out a NIC port. - */ -static void -flush_port_queue(struct thread_info *tx, uint16_t port) { - uint16_t i, sent; - volatile struct tx_stats *tx_stats; - - if (tx->port_tx_buf[port].count == 0) - return; - - tx_stats = &(ports->tx_stats); - sent = rte_eth_tx_burst(port, tx->queue_id, tx->port_tx_buf[port].buffer, tx->port_tx_buf[port].count); - if (unlikely(sent < tx->port_tx_buf[port].count)) { - for (i = sent; i < tx->port_tx_buf[port].count; i++) { - drop_packet(tx->port_tx_buf[port].buffer[i]); - } - tx_stats->tx_drop[port] += (tx->port_tx_buf[port].count - sent); - } - tx_stats->tx[port] += sent; - - tx->port_tx_buf[port].count = 0; -} - -/** - * This function take a service id input and returns an instance id to route the packet to - * This uses the packet's RSS Hash mod the number of available services to decide - * Returns 0 (manager reserved ID) if no NFs are available from the desired service - */ -static inline uint16_t -service_to_nf_map(uint16_t service_id, struct rte_mbuf *pkt) { - uint16_t num_nfs_available = nf_per_service_count[service_id]; - - if (num_nfs_available == 0) - return 0; - - uint16_t instance_index = pkt->hash.rss % num_nfs_available; - uint16_t instance_id = service_to_nf[service_id][instance_index]; - return instance_id; -} - -/** - * Add a packet to a buffer destined for an NF's RX queue. - */ -static inline void -enqueue_nf_packet(struct thread_info *thread, uint16_t dst_service_id, struct rte_mbuf *pkt) { - struct client *cl; - uint16_t dst_instance_id; - - // map service to instance and check one exists - dst_instance_id = service_to_nf_map(dst_service_id, pkt); - if (dst_instance_id == 0) { - drop_packet(pkt); - return; - } - - // Ensure destination NF is running and ready to receive packets - cl = &clients[dst_instance_id]; - if (!is_valid_nf(cl)) { - drop_packet(pkt); - return; - } - - thread->nf_rx_buf[dst_instance_id].buffer[thread->nf_rx_buf[dst_instance_id].count++] = pkt; - if (thread->nf_rx_buf[dst_instance_id].count == PACKET_READ_SIZE) { - flush_nf_queue(thread, dst_instance_id); - } -} - -/** - * Add a packet to a buffer destined for a port's TX queue. - */ -static inline void -enqueue_port_packet(struct thread_info *tx, uint16_t port, struct rte_mbuf *buf) { - tx->port_tx_buf[port].buffer[tx->port_tx_buf[port].count++] = buf; - if (tx->port_tx_buf[port].count == PACKET_READ_SIZE) { - flush_port_queue(tx, port); - } -} - -/* - * Process a packet with action NEXT - */ -static inline void -process_next_action_packet(struct thread_info *tx, struct rte_mbuf *pkt, struct client *cl) { - struct onvm_flow_entry *flow_entry; - struct onvm_service_chain *sc; - struct onvm_pkt_meta *meta = onvm_get_pkt_meta(pkt); - int ret; - - ret = onvm_flow_dir_get_pkt(pkt, &flow_entry); - if (ret >= 0) { - sc = flow_entry->sc; - meta->action = onvm_sc_next_action(sc, pkt); - meta->destination = onvm_sc_next_destination(sc, pkt); - } - else { - meta->action = onvm_sc_next_action(default_chain, pkt); - meta->destination = onvm_sc_next_destination(default_chain, pkt); - } - - switch(meta->action) { - case ONVM_NF_ACTION_DROP: - // if the packet is drop, then is 0 - // and ! is 1. - cl->stats.act_drop += !drop_packet(pkt); - break; - case ONVM_NF_ACTION_TONF: - cl->stats.act_tonf++; - enqueue_nf_packet(tx, meta->destination, pkt); - break; - case ONVM_NF_ACTION_OUT: - cl->stats.act_out++; - enqueue_port_packet(tx, meta->destination, pkt); - break; - default: - break; - } - (meta->chain_index)++; -} - -/* - * This function takes a group of packets and routes them - * to the first client process. Simply forwarding the packets - * without checking any of the packet contents. - */ -static void -process_rx_packet_batch(struct thread_info *rx, struct rte_mbuf *pkts[], uint16_t rx_count) { - uint16_t i; - struct onvm_pkt_meta *meta; - struct onvm_flow_entry *flow_entry; - struct onvm_service_chain *sc; - int ret; - - for (i = 0; i < rx_count; i++) { - meta = (struct onvm_pkt_meta*) &(((struct rte_mbuf*)pkts[i])->udata64); - (void)meta; - meta->src = 0; - meta->chain_index = 0; - ret = onvm_flow_dir_get_pkt(pkts[i], &flow_entry); - if (ret >= 0) { - sc = flow_entry->sc; - meta->action = onvm_sc_next_action(sc, pkts[i]); - meta->destination = onvm_sc_next_destination(sc, pkts[i]); - } - else { - meta->action = onvm_sc_next_action(default_chain, pkts[i]); - meta->destination = onvm_sc_next_destination(default_chain, pkts[i]); - } - /* PERF: this might hurt performance since it will cause cache - * invalidations. Ideally the data modified by the NF manager - * would be a different line than that modified/read by NFs. - * That may not be possible. - */ - - (meta->chain_index)++; - enqueue_nf_packet(rx, meta->destination, pkts[i]); - } - - for (i = 0; i < MAX_CLIENTS; i++) { - if (rx->nf_rx_buf[i].count != 0) { - flush_nf_queue(rx, i); - } - } -} - -/* - * Handle the packets from a client. Check what the next action is - * and forward the packet either to the NIC or to another NF Client. - */ -static void -process_tx_packet_batch(struct thread_info *tx, struct rte_mbuf *pkts[], uint16_t tx_count, struct client *cl) { - uint16_t i; - struct onvm_pkt_meta *meta; - - for (i = 0; i < tx_count; i++) { - meta = (struct onvm_pkt_meta*) &(((struct rte_mbuf*)pkts[i])->udata64); - meta->src = cl->instance_id; - if (meta->action == ONVM_NF_ACTION_DROP) { - // if the packet is drop, then is 0 - // and ! is 1. - cl->stats.act_drop += !drop_packet(pkts[i]); - } else if (meta->action == ONVM_NF_ACTION_NEXT) { - /* TODO: Here we drop the packet : there will be a flow table - in the future to know what to do with the packet next */ - cl->stats.act_next++; - process_next_action_packet(tx, pkts[i], cl); - } else if (meta->action == ONVM_NF_ACTION_TONF) { - cl->stats.act_tonf++; - enqueue_nf_packet(tx, meta->destination, pkts[i]); - } else if (meta->action == ONVM_NF_ACTION_OUT) { - cl->stats.act_out++; - enqueue_port_packet(tx, meta->destination, pkts[i]); - } else { - printf("ERROR invalid action : this shouldn't happen.\n"); - drop_packet(pkts[i]); - return; - } - } -} /* * Function to receive packets from the NIC @@ -647,11 +83,15 @@ process_tx_packet_batch(struct thread_info *tx, struct rte_mbuf *pkts[], uint16_ */ static int rx_thread_main(void *arg) { - uint16_t i, j, rx_count; + uint16_t i, rx_count; struct rte_mbuf *pkts[PACKET_READ_SIZE]; struct thread_info *rx = (struct thread_info*)arg; - RTE_LOG(INFO, APP, "Core %d: Running RX thread for RX queue %d\n", rte_lcore_id(), rx->queue_id); + RTE_LOG(INFO, + APP, + "Core %d: Running RX thread for RX queue %d\n", + rte_lcore_id(), + rx->queue_id); for (;;) { /* Read ports */ @@ -663,12 +103,10 @@ rx_thread_main(void *arg) { /* Now process the NIC packets read */ if (likely(rx_count > 0)) { // If there is no running NF, we drop all the packets of the batch. - if(!num_clients) { - for(j = 0; j < rx_count; j++) { - drop_packet(pkts[j]); - } + if (!num_clients) { + onvm_pkt_drop_batch(pkts, rx_count); } else { - process_rx_packet_batch(rx, pkts, rx_count); + onvm_pkt_process_rx_batch(rx, pkts, rx_count); } } } @@ -686,9 +124,18 @@ tx_thread_main(void *arg) { struct thread_info* tx = (struct thread_info*)arg; if (tx->first_cl == tx->last_cl - 1) { - RTE_LOG(INFO, APP, "Core %d: Running TX thread for NF %d\n", rte_lcore_id(), tx->first_cl); + RTE_LOG(INFO, + APP, + "Core %d: Running TX thread for NF %d\n", + rte_lcore_id(), + tx->first_cl); } else if (tx->first_cl < tx->last_cl) { - RTE_LOG(INFO, APP, "Core %d: Running TX thread for NFs %d to %d\n", rte_lcore_id(), tx->first_cl, tx->last_cl-1); + RTE_LOG(INFO, + APP, + "Core %d: Running TX thread for NFs %d to %d\n", + rte_lcore_id(), + tx->first_cl, + tx->last_cl-1); } for (;;) { @@ -696,7 +143,7 @@ tx_thread_main(void *arg) { for (i = tx->first_cl; i < tx->last_cl; i++) { tx_count = PACKET_READ_SIZE; cl = &clients[i]; - if (!is_valid_nf(cl)) + if (!onvm_nf_is_valid(cl)) continue; /* try dequeuing max possible packets first, if that fails, get the * most we can. Loop body should only execute once, maximum */ @@ -708,27 +155,24 @@ tx_thread_main(void *arg) { /* Now process the Client packets read */ if (likely(tx_count > 0)) { - process_tx_packet_batch(tx, pkts, tx_count, cl); + onvm_pkt_process_tx_batch(tx, pkts, tx_count, cl); } } /* Send a burst to every port */ - for (i = 0; i < ports->num_ports; i++) { - if (tx->port_tx_buf[i].count != 0) { - flush_port_queue(tx, i); - } - } + onvm_pkt_flush_all_ports(tx); - /* Send a burst to every client */ - for (i = 0; i < MAX_CLIENTS; i++) { - if(tx->nf_rx_buf[i].count != 0) { - flush_nf_queue(tx, i); - } - } + /* Send a burst to every NF */ + onvm_pkt_flush_all_nfs(tx); } + return 0; } + +/*******************************Main function*********************************/ + + int main(int argc, char *argv[]) { unsigned cur_lcore, rx_lcores, tx_lcores; @@ -744,7 +188,7 @@ main(int argc, char *argv[]) { RTE_LOG(INFO, APP, "Finished Process Init.\n"); /* clear statistics */ - clear_stats(); + onvm_stats_clear_all_clients(); /* Reserve n cores for: 1 Stats, 1 final Tx out, and ONVM_NUM_RX_THREADS for Rx */ cur_lcore = rte_lcore_id(); @@ -768,11 +212,16 @@ main(int argc, char *argv[]) { * We want to distribute the number of running NFs across available * TX threads */ - if (num_clients == 0) clients_per_tx = ceil((float)MAX_CLIENTS/tx_lcores), temp_num_clients = (unsigned)MAX_CLIENTS; - else clients_per_tx = ceil((float)num_clients/tx_lcores), temp_num_clients = (unsigned)num_clients; + if (num_clients == 0) { + clients_per_tx = ceil((float)MAX_CLIENTS/tx_lcores); + temp_num_clients = (unsigned)MAX_CLIENTS; + } else { + clients_per_tx = ceil((float)num_clients/tx_lcores); + temp_num_clients = (unsigned)num_clients; + } for (i = 0; i < tx_lcores; i++) { - struct thread_info *tx = calloc(1,sizeof(struct thread_info)); + struct thread_info *tx = calloc(1, sizeof(struct thread_info)); tx->queue_id = i; tx->port_tx_buf = calloc(RTE_MAX_ETHPORTS, sizeof(struct packet_buf)); tx->nf_rx_buf = calloc(MAX_CLIENTS, sizeof(struct packet_buf)); @@ -780,7 +229,11 @@ main(int argc, char *argv[]) { tx->last_cl = RTE_MIN((i+1) * clients_per_tx + 1, temp_num_clients); cur_lcore = rte_get_next_lcore(cur_lcore, 1, 1); if (rte_eal_remote_launch(tx_thread_main, (void*)tx, cur_lcore) == -EBUSY) { - RTE_LOG(ERR, APP, "Core %d is already busy, can't use for client %d TX\n", cur_lcore, tx->first_cl); + RTE_LOG(ERR, + APP, + "Core %d is already busy, can't use for client %d TX\n", + cur_lcore, + tx->first_cl); return -1; } } @@ -789,11 +242,15 @@ main(int argc, char *argv[]) { for (i = 0; i < rx_lcores; i++) { struct thread_info *rx = calloc(1, sizeof(struct thread_info)); rx->queue_id = i; - rx->port_tx_buf = NULL; - rx->nf_rx_buf = calloc(MAX_CLIENTS, sizeof(struct packet_buf)); + rx->port_tx_buf = NULL; + rx->nf_rx_buf = calloc(MAX_CLIENTS, sizeof(struct packet_buf)); cur_lcore = rte_get_next_lcore(cur_lcore, 1, 1); if (rte_eal_remote_launch(rx_thread_main, (void *)rx, cur_lcore) == -EBUSY) { - RTE_LOG(ERR, APP, "Core %d is already busy, can't use for RX queue id %d\n", cur_lcore, rx->queue_id); + RTE_LOG(ERR, + APP, + "Core %d is already busy, can't use for RX queue id %d\n", + cur_lcore, + rx->queue_id); return -1; } } diff --git a/onvm/onvm_mgr/args.c b/onvm/onvm_mgr/onvm_args.c similarity index 87% rename from onvm/onvm_mgr/args.c rename to onvm/onvm_mgr/onvm_args.c index 70bf5d680..ba9709194 100644 --- a/onvm/onvm_mgr/args.c +++ b/onvm/onvm_mgr/onvm_args.c @@ -36,22 +36,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * args.c - argument processing for simple onvm ********************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include +/****************************************************************************** + + onvm_args.c + + File containing the function parsing all DPDK and ONVM arguments. + + +******************************************************************************/ + + +#include "onvm_mgr/onvm_args.h" + + +/******************************Global variables*******************************/ -#include "shared/common.h" -#include "onvm_mgr/args.h" -#include "onvm_mgr/init.h" /* global var for number of clients - extern in header init.h */ uint16_t num_clients; @@ -68,8 +70,99 @@ uint8_t is_static_clients; /* global var for program name */ static const char *progname; -/** - * Prints out usage information to stdout */ + +/***********************Internal Functions prototypes*************************/ + + +static void +usage(void); + + +static int +parse_portmask(uint8_t max_ports, const char *portmask); + + +static int +parse_default_service(const char *services); + + +static int +parse_num_services(const char *services); + + +#ifdef USE_STATIC_IDS + +static int +parse_num_clients(const char *clients); + +#endif + + +/*********************************Interfaces**********************************/ + + +int +parse_app_args(uint8_t max_ports, int argc, char *argv[]) { + int option_index, opt; + char **argvopt = argv; + static struct option lgopts[] = { /* no long options */ + {NULL, 0, 0, 0 } + }; + progname = argv[0]; + is_static_clients = DYNAMIC_CLIENTS; + +#ifdef USE_STATIC_IDS + while ((opt = getopt_long(argc, argvopt, "n:r:p:d:", lgopts, &option_index)) != EOF) { +#else + while ((opt = getopt_long(argc, argvopt, "r:p:d:", lgopts, &option_index)) != EOF) { +#endif + switch (opt) { + case 'p': + if (parse_portmask(max_ports, optarg) != 0) { + usage(); + return -1; + } + break; +#ifdef USE_STATIC_IDS + case 'n': + if (parse_num_clients(optarg) != 0) { + usage(); + return -1; + } + break; +#endif + case 'r': + if (parse_num_services(optarg) != 0) { + usage(); + return -1; + } + break; + case 'd': + if (parse_default_service(optarg) != 0) { + usage(); + return -1; + } + break; + default: + printf("ERROR: Unknown option '%c'\n", opt); + usage(); + return -1; + } + } + + if (is_static_clients == STATIC_CLIENTS + && num_clients == 0) { + usage(); + return -1; + } + + return 0; +} + + +/*****************************Internal functions******************************/ + + static void usage(void) { printf( @@ -86,12 +179,7 @@ usage(void) { , progname); } -/** - * The ports to be used by the application are passed in - * the form of a bitmask. This function parses the bitmask - * and places the port numbers to be used into the port[] - * array variable - */ + static int parse_portmask(uint8_t max_ports, const char *portmask) { char *end = NULL; @@ -126,9 +214,7 @@ parse_portmask(uint8_t max_ports, const char *portmask) { return 0; } -/** - * Parse the default service to send packets to - */ + static int parse_default_service(const char *services) { char *end = NULL; @@ -142,9 +228,7 @@ parse_default_service(const char *services) { return 0; } -/** - * Parse the number of services to allow from command line args - */ + static int parse_num_services(const char *services) { char *end = NULL; @@ -158,11 +242,8 @@ parse_num_services(const char *services) { return 0; } + #ifdef USE_STATIC_IDS -/** - * Take the number of clients parameter passed to the app - * and convert to a number to store in the num_clients variable - */ static int parse_num_clients(const char *clients) { char *end = NULL; @@ -181,67 +262,3 @@ parse_num_clients(const char *clients) { return 0; } #endif - -/** - * The application specific arguments follow the DPDK-specific - * arguments which are stripped by the DPDK init. This function - * processes these application arguments, printing usage info - * on error. - */ -int -parse_app_args(uint8_t max_ports, int argc, char *argv[]) { - int option_index, opt; - char **argvopt = argv; - static struct option lgopts[] = { /* no long options */ - {NULL, 0, 0, 0 } - }; - progname = argv[0]; - is_static_clients = DYNAMIC_CLIENTS; - -#ifdef USE_STATIC_IDS - while ((opt = getopt_long(argc, argvopt, "n:r:p:d:", lgopts, &option_index)) != EOF) { -#else - while ((opt = getopt_long(argc, argvopt, "r:p:d:", lgopts, &option_index)) != EOF) { -#endif - switch (opt) { - case 'p': - if (parse_portmask(max_ports, optarg) != 0) { - usage(); - return -1; - } - break; -#ifdef USE_STATIC_IDS - case 'n': - if (parse_num_clients(optarg) != 0) { - usage(); - return -1; - } - break; -#endif - case 'r': - if (parse_num_services(optarg) != 0) { - usage(); - return -1; - } - break; - case 'd': - if (parse_default_service(optarg) != 0) { - usage(); - return -1; - } - break; - default: - printf("ERROR: Unknown option '%c'\n", opt); - usage(); - return -1; - } - } - - if (is_static_clients == STATIC_CLIENTS - && num_clients == 0) { - usage(); - return -1; - } - - return 0; -} diff --git a/onvm/onvm_mgr/args.h b/onvm/onvm_mgr/onvm_args.h similarity index 82% rename from onvm/onvm_mgr/args.h rename to onvm/onvm_mgr/onvm_args.h index 040f06199..064d9a987 100644 --- a/onvm/onvm_mgr/args.h +++ b/onvm/onvm_mgr/onvm_args.h @@ -36,14 +36,29 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * args.h - argument processing for simple onvm ********************************************************************/ -#ifndef _ARGS_H_ -#define _ARGS_H_ + +/****************************************************************************** + + onvm_args.h + + Header file with functions for parsing DPDK and ONVM command-line arguments + + +******************************************************************************/ + + +#ifndef _ONVM_ARGS_H_ +#define _ONVM_ARGS_H_ + +#include "getopt.h" + +#include "shared/onvm_includes.h" +#include "onvm_mgr/onvm_init.h" #define DEFAULT_SERVICE_ID 1 int parse_app_args(uint8_t max_ports, int argc, char *argv[]); -#endif // _ARGS_H_ +#endif // _ONVM_ARGS_H_ diff --git a/onvm/onvm_mgr/init.c b/onvm/onvm_mgr/onvm_init.c similarity index 87% rename from onvm/onvm_mgr/init.c rename to onvm/onvm_mgr/onvm_init.c index bd8de0505..2e3da11bd 100644 --- a/onvm/onvm_mgr/init.c +++ b/onvm/onvm_mgr/onvm_init.c @@ -36,94 +36,142 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * init.c - initialization for simple onvm ********************************************************************/ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "shared/common.h" -#include "onvm_mgr/args.h" -#include "onvm_mgr/init.h" -#include "shared/onvm_sc_mgr.h" -#include "shared/onvm_sc_common.h" -#include "shared/onvm_flow_table.h" -#include "shared/onvm_flow_dir.h" - -#define MBUFS_PER_CLIENT 1536 -#define MBUFS_PER_PORT 1536 -#define MBUF_CACHE_SIZE 512 -#define MBUF_OVERHEAD (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) -#define RX_MBUF_DATA_SIZE 2048 -#define MBUF_SIZE (RX_MBUF_DATA_SIZE + MBUF_OVERHEAD) - -#define NF_INFO_SIZE sizeof(struct onvm_nf_info) -#define NF_INFO_CACHE 8 - -#define RTE_MP_RX_DESC_DEFAULT 512 -#define RTE_MP_TX_DESC_DEFAULT 512 -#define CLIENT_QUEUE_RINGSIZE 128 - -#define NO_FLAGS 0 - -/* The mbuf pool for packet rx */ -struct rte_mempool *pktmbuf_pool; -/* mbuf pool for nf info structs */ -struct rte_mempool *nf_info_pool; +/****************************************************************************** -/* ring buffer for new clients coming up */ -struct rte_ring *nf_info_queue; + onvm_init.c -/* array of info/queues for clients */ -struct client *clients = NULL; + File containing initialization functions. -/* 2D array mapping services to NFs, extern in init.h */ -uint16_t **service_to_nf; -/* Array tracking number of NFs active per service, extern in init.h */ -uint16_t *nf_per_service_count; +******************************************************************************/ + + +#include "onvm_mgr/onvm_init.h" -/* the port details */ + +/********************************Global variables*****************************/ + + +struct client *clients = NULL; struct port_info *ports = NULL; +struct rte_mempool *pktmbuf_pool; +struct rte_mempool *nf_info_pool; +struct rte_ring *nf_info_queue; +uint16_t **services; +uint16_t *nf_per_service_count; struct client_tx_stats *clients_stats; - struct onvm_service_chain *default_chain; struct onvm_service_chain **default_sc_p; + +/*************************Internal Functions Prototypes***********************/ + + +static int init_mbuf_pools(void); +static int init_client_info_pool(void); +static int init_port(uint8_t port_num); +static int init_shm_rings(void); +static int init_info_queue(void); +static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask); + + +/*********************************Interfaces**********************************/ + + +int +init(int argc, char *argv[]) { + int retval; + const struct rte_memzone *mz; + const struct rte_memzone *mz_scp; + uint8_t i, total_ports; + + /* init EAL, parsing EAL args */ + retval = rte_eal_init(argc, argv); + if (retval < 0) + return -1; + argc -= retval; + argv += retval; + + /* get total number of ports */ + total_ports = rte_eth_dev_count(); + + /* set up array for client tx data */ + mz = rte_memzone_reserve(MZ_CLIENT_INFO, sizeof(*clients_stats), + rte_socket_id(), NO_FLAGS); + if (mz == NULL) + rte_exit(EXIT_FAILURE, "Cannot reserve memory zone for client information\n"); + memset(mz->addr, 0, sizeof(*clients_stats)); + clients_stats = mz->addr; + + /* set up ports info */ + ports = rte_malloc(MZ_PORT_INFO, sizeof(*ports), 0); + if (ports == NULL) + rte_exit(EXIT_FAILURE, "Cannot allocate memory for ports details\n"); + + /* parse additional, application arguments */ + retval = parse_app_args(total_ports, argc, argv); + if (retval != 0) + return -1; + + /* initialise mbuf pools */ + retval = init_mbuf_pools(); + if (retval != 0) + rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n"); + + /* initialise client info pool */ + retval = init_client_info_pool(); + if (retval != 0) { + rte_exit(EXIT_FAILURE, "Cannot create client info mbuf pool: %s\n", rte_strerror(rte_errno)); + } + + /* now initialise the ports we will use */ + for (i = 0; i < ports->num_ports; i++) { + retval = init_port(ports->id[i]); + if (retval != 0) + rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n", + (unsigned)i); + } + + check_all_ports_link_status(ports->num_ports, (~0x0)); + + /* initialise the client queues/rings for inter-eu comms */ + init_shm_rings(); + + /* initialise a queue for newly created NFs */ + init_info_queue(); + + /*initialize a default service chain*/ + default_chain = onvm_sc_create(); + retval = onvm_sc_append_entry(default_chain, ONVM_NF_ACTION_TONF, 1); + if (retval == ENOSPC) { + printf("chain length can not be larger than the maximum chain length\n"); + exit(1); + } + printf("Default service chain: send to sdn NF\n"); + + /* set up service chain pointer shared to NFs*/ + mz_scp = rte_memzone_reserve(MZ_SCP_INFO, sizeof(struct onvm_service_chain *), + rte_socket_id(), NO_FLAGS); + if (mz_scp == NULL) + rte_exit(EXIT_FAILURE, "Canot reserve memory zone for service chain pointer\n"); + memset(mz_scp->addr, 0, sizeof(struct onvm_service_chain *)); + default_sc_p = mz_scp->addr; + *default_sc_p = default_chain; + onvm_sc_print(default_chain); + + onvm_flow_dir_init(); + + return 0; +} + + +/*****************************Internal functions******************************/ + + /** * Initialise the mbuf pool for packet reception for the NIC, and any other * buffer pools needed by the app - currently none. @@ -246,15 +294,15 @@ init_shm_rings(void) { if (clients == NULL) rte_exit(EXIT_FAILURE, "Cannot allocate memory for client program details\n"); - service_to_nf = rte_calloc("service to nf map", + services = rte_calloc("service to nf map", num_services, sizeof(uint16_t*), 0); for (i = 0; i < num_services; i++) { - service_to_nf[i] = rte_calloc("one service NFs", + services[i] = rte_calloc("one service NFs", MAX_CLIENTS_PER_SERVICE, sizeof(uint16_t), 0); } nf_per_service_count = rte_calloc("count of NFs active per service", num_services, sizeof(uint16_t), 0); - if (service_to_nf == NULL || nf_per_service_count == NULL) + if (services == NULL || nf_per_service_count == NULL) rte_exit(EXIT_FAILURE, "Cannot allocate memory for service to NF mapping\n"); for (i = 0; i < MAX_CLIENTS; i++) { @@ -355,88 +403,3 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) { * Main init function for the multi-process server app, * calls subfunctions to do each stage of the initialisation. */ -int -init(int argc, char *argv[]) { - int retval; - const struct rte_memzone *mz; - const struct rte_memzone *mz_scp; - uint8_t i, total_ports; - - /* init EAL, parsing EAL args */ - retval = rte_eal_init(argc, argv); - if (retval < 0) - return -1; - argc -= retval; - argv += retval; - - /* get total number of ports */ - total_ports = rte_eth_dev_count(); - - /* set up array for client tx data */ - mz = rte_memzone_reserve(MZ_CLIENT_INFO, sizeof(*clients_stats), - rte_socket_id(), NO_FLAGS); - if (mz == NULL) - rte_exit(EXIT_FAILURE, "Cannot reserve memory zone for client information\n"); - memset(mz->addr, 0, sizeof(*clients_stats)); - clients_stats = mz->addr; - - /* set up ports info */ - ports = rte_malloc(MZ_PORT_INFO, sizeof(*ports), 0); - if (ports == NULL) - rte_exit(EXIT_FAILURE, "Cannot allocate memory for ports details\n"); - - /* parse additional, application arguments */ - retval = parse_app_args(total_ports, argc, argv); - if (retval != 0) - return -1; - - /* initialise mbuf pools */ - retval = init_mbuf_pools(); - if (retval != 0) - rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n"); - - /* initialise client info pool */ - retval = init_client_info_pool(); - if (retval != 0) { - rte_exit(EXIT_FAILURE, "Cannot create client info mbuf pool: %s\n", rte_strerror(rte_errno)); - } - - /* now initialise the ports we will use */ - for (i = 0; i < ports->num_ports; i++) { - retval = init_port(ports->id[i]); - if (retval != 0) - rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n", - (unsigned)i); - } - - check_all_ports_link_status(ports->num_ports, (~0x0)); - - /* initialise the client queues/rings for inter-eu comms */ - init_shm_rings(); - - /* initialise a queue for newly created NFs */ - init_info_queue(); - - /*initialize a default service chain*/ - default_chain = onvm_sc_create(); - retval = onvm_sc_append_entry(default_chain, ONVM_NF_ACTION_TONF, 1); - if (retval == ENOSPC) { - printf("chain length can not be larger than the maximum chain length\n"); - exit(1); - } - printf("Default service chain: send to sdn NF\n"); - - /* set up service chain pointer shared to NFs*/ - mz_scp = rte_memzone_reserve(MZ_SCP_INFO, sizeof(struct onvm_service_chain *), - rte_socket_id(), NO_FLAGS); - if (mz_scp == NULL) - rte_exit(EXIT_FAILURE, "Canot reserve memory zone for service chain pointer\n"); - memset(mz_scp->addr, 0, sizeof(struct onvm_service_chain *)); - default_sc_p = mz_scp->addr; - *default_sc_p = default_chain; - onvm_sc_print(default_chain); - - onvm_flow_dir_init(); - - return 0; -} diff --git a/onvm/onvm_mgr/init.h b/onvm/onvm_mgr/onvm_init.h similarity index 69% rename from onvm/onvm_mgr/init.h rename to onvm/onvm_mgr/onvm_init.h index 6d3114b8c..fbf7e18da 100644 --- a/onvm/onvm_mgr/init.h +++ b/onvm/onvm_mgr/onvm_init.h @@ -36,22 +36,74 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * init.h - initialization for simple onvm ********************************************************************/ -#ifndef _INIT_H_ -#define _INIT_H_ -/* - * #include - * #include "args.h" - */ +/****************************************************************************** + + onvm_init.h + + Header for the initialisation function and global variables and + data structures. + + +******************************************************************************/ + + +#ifndef _ONVM_INIT_H_ +#define _ONVM_INIT_H_ + + +/********************************DPDK library*********************************/ + +#include +#include +#include +#include +#include +#include + + +/*****************************Internal library********************************/ + + +#include "onvm_mgr/onvm_args.h" +#include "shared/onvm_includes.h" +#include "shared/common.h" +#include "shared/onvm_sc_mgr.h" +#include "shared/onvm_sc_common.h" +#include "shared/onvm_flow_table.h" +#include "shared/onvm_flow_dir.h" + + +/***********************************Macros************************************/ + + +#define MBUFS_PER_CLIENT 1536 +#define MBUFS_PER_PORT 1536 +#define MBUF_CACHE_SIZE 512 +#define MBUF_OVERHEAD (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define RX_MBUF_DATA_SIZE 2048 +#define MBUF_SIZE (RX_MBUF_DATA_SIZE + MBUF_OVERHEAD) + +#define NF_INFO_SIZE sizeof(struct onvm_nf_info) +#define NF_INFO_CACHE 8 + +#define RTE_MP_RX_DESC_DEFAULT 512 +#define RTE_MP_TX_DESC_DEFAULT 512 +#define CLIENT_QUEUE_RINGSIZE 128 + +#define NO_FLAGS 0 #define ONVM_NUM_RX_THREADS 1 #define DYNAMIC_CLIENTS 0 #define STATIC_CLIENTS 1 + +/******************************Data structures********************************/ + + /* * Define a client structure with all needed info, including * stats from the clients. @@ -77,9 +129,6 @@ struct client { } stats; }; -extern struct client *clients; - -extern struct rte_ring *nf_info_queue; /* * Shared port info, including statistics information for display by server. @@ -96,11 +145,13 @@ struct rx_stats{ uint64_t rx[RTE_MAX_ETHPORTS]; }; + struct tx_stats{ uint64_t tx[RTE_MAX_ETHPORTS]; uint64_t tx_drop[RTE_MAX_ETHPORTS]; }; + struct port_info { uint8_t num_ports; uint8_t id[RTE_MAX_ETHPORTS]; @@ -108,6 +159,15 @@ struct port_info { volatile struct tx_stats tx_stats; }; + + +/*************************External global variables***************************/ + + +extern struct client *clients; + +extern struct rte_ring *nf_info_queue; + /* the shared port information: port numbers, rx and tx stats etc. */ extern struct port_info *ports; @@ -115,12 +175,24 @@ extern struct rte_mempool *pktmbuf_pool; extern uint16_t num_clients; extern uint16_t num_services; extern uint16_t default_service; -extern uint16_t **service_to_nf; +extern uint16_t **services; extern uint16_t *nf_per_service_count; extern unsigned num_sockets; extern struct onvm_service_chain *default_chain; extern struct onvm_ft *sdn_ft; + +/**********************************Functions**********************************/ + +/* + * Function that initialize all data structures, memory mapping and global + * variables. + * + * Input : the number of arguments (following C conventions) + * an array of the arguments as strings + * Output : an error code + * + */ int init(int argc, char *argv[]); -#endif // _INIT_H_ +#endif // _ONVM_INIT_H_ diff --git a/onvm/onvm_mgr/onvm_mgr.h b/onvm/onvm_mgr/onvm_mgr.h new file mode 100644 index 000000000..c02509996 --- /dev/null +++ b/onvm/onvm_mgr/onvm_mgr.h @@ -0,0 +1,129 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_mgr.h + + + Header file containing all shared headers and data structures + + +******************************************************************************/ + + +#ifndef _ONVM_MGR_H_ +#define _ONVM_MGR_H_ + + +/******************************Standard C library*****************************/ + + +#include +#include +#include + + +/********************************DPDK library*********************************/ + + +#include +#include +#include +#include + + +/******************************Internal headers*******************************/ + + +#include "onvm_mgr/onvm_args.h" +#include "onvm_mgr/onvm_init.h" +#include "shared/onvm_includes.h" +#include "shared/onvm_sc_mgr.h" +#include "shared/onvm_flow_table.h" +#include "shared/onvm_flow_dir.h" + + +/***********************************Macros************************************/ + + +#define PACKET_READ_SIZE ((uint16_t)32) + +#define TO_PORT 0 +#define TO_CLIENT 1 + + +/***************************Shared global variables***************************/ + + +/* ID to be assigned to the next NF that starts */ +extern uint16_t next_instance_id; + + +/*******************************Data Structures*******************************/ + + +/* + * Local buffers to put packets in, used to send packets in bursts to the + * clients or to the NIC + */ +struct packet_buf { + struct rte_mbuf *buffer[PACKET_READ_SIZE]; + uint16_t count; +}; + + +/** Thread state. This specifies which NFs the thread will handle and + * includes the packet buffers used by the thread for NFs and ports. + */ +struct thread_info { + unsigned queue_id; + unsigned first_cl; + unsigned last_cl; + /* FIXME: This is confusing since it is non-inclusive. It would be + * better to have this take the first client and the number + * of consecutive clients after it to handle. + */ + struct packet_buf *nf_rx_buf; + struct packet_buf *port_tx_buf; +}; + +#endif // _ONVM_MGR_H_ diff --git a/onvm/onvm_mgr/onvm_nf.c b/onvm/onvm_mgr/onvm_nf.c new file mode 100644 index 000000000..cedf6f1f4 --- /dev/null +++ b/onvm/onvm_mgr/onvm_nf.c @@ -0,0 +1,240 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_nf.c + + This file contains all functions related to NF management. + +******************************************************************************/ + + +#include "onvm_mgr.h" +#include "onvm_nf.h" +#include "onvm_stats.h" + +uint16_t next_instance_id = 0; + + +/************************Internal functions prototypes************************/ + + +/* + * Function starting a NF. + * + * Input : a pointer to the NF's informations + * Output : an error code + * + */ +inline static int +onvm_nf_start(struct onvm_nf_info *nf_info); + + +/* + * Function stopping a NF. + * + * Input : a pointer to the NF's informations + * Output : an error code + * + */ +inline static int +onvm_nf_stop(struct onvm_nf_info *nf_info); + + +/********************************Interfaces***********************************/ + + +inline int +onvm_nf_is_valid(struct client *cl) { + return cl && cl->info && cl->info->status == NF_RUNNING; +} + + +uint16_t +onvm_nf_next_instance_id(void) { + struct client *cl; + while (next_instance_id < MAX_CLIENTS) { + cl = &clients[next_instance_id]; + if (!onvm_nf_is_valid(cl)) + break; + next_instance_id++; + } + return next_instance_id; +} + + +void +onvm_nf_check_status(void) { + int i; + void *new_nfs[MAX_CLIENTS]; + struct onvm_nf_info *nf; + int num_new_nfs = rte_ring_count(nf_info_queue); + + if (rte_ring_dequeue_bulk(nf_info_queue, new_nfs, num_new_nfs) != 0) + return; + + for (i = 0; i < num_new_nfs; i++) { + nf = (struct onvm_nf_info *) new_nfs[i]; + + if (nf->status == NF_WAITING_FOR_ID) { + if (!onvm_nf_start(nf)) + num_clients++; + } else if (nf->status == NF_STOPPED) { + if (!onvm_nf_stop(nf)) + num_clients--; + } + } +} + + +inline uint16_t +onvm_nf_service_to_nf_map(uint16_t service_id, struct rte_mbuf *pkt) { + uint16_t num_nfs_available = nf_per_service_count[service_id]; + + if (num_nfs_available == 0) + return 0; + + if (pkt == NULL) + return 0; + + uint16_t instance_index = pkt->hash.rss % num_nfs_available; + uint16_t instance_id = services[service_id][instance_index]; + return instance_id; +} + + +/******************************Internal functions*****************************/ + + +inline static int +onvm_nf_start(struct onvm_nf_info *nf_info) { + // TODO dynamically allocate memory here - make rx/tx ring + // take code from init_shm_rings in init.c + // flush rx/tx queue at the this index to start clean? + + if(nf_info == NULL) + return 1; + + // if NF passed its own id on the command line, don't assign here + // assume user is smart enough to avoid duplicates + uint16_t nf_id = nf_info->instance_id == (uint16_t)NF_NO_ID + ? onvm_nf_next_instance_id() + : nf_info->instance_id; + + if (nf_id >= MAX_CLIENTS) { + // There are no more available IDs for this NF + nf_info->status = NF_NO_IDS; + return 1; + } + + if (onvm_nf_is_valid(&clients[nf_id])) { + // This NF is trying to declare an ID already in use + nf_info->status = NF_ID_CONFLICT; + return 1; + } + + // Keep reference to this NF in the manager + nf_info->instance_id = nf_id; + clients[nf_id].info = nf_info; + clients[nf_id].instance_id = nf_id; + + // Register this NF running within its service + uint16_t service_count = nf_per_service_count[nf_info->service_id]++; + services[nf_info->service_id][service_count] = nf_id; + + // Let the NF continue its init process + nf_info->status = NF_STARTING; + return 0; +} + + +inline static int +onvm_nf_stop(struct onvm_nf_info *nf_info) { + uint16_t nf_id; + uint16_t service_id; + int mapIndex; + struct rte_mempool *nf_info_mp; + + if(nf_info == NULL) + return 1; + + nf_id = nf_info->instance_id; + service_id = nf_info->service_id; + + /* Clean up dangling pointers to info struct */ + clients[nf_id].info = NULL; + + /* Reset stats */ + onvm_stats_clear_client(nf_id); + + /* Remove this NF from the service map. + * Need to shift all elements past it in the array left to avoid gaps */ + nf_per_service_count[service_id]--; + for (mapIndex = 0; mapIndex < MAX_CLIENTS_PER_SERVICE; mapIndex++) { + if (services[service_id][mapIndex] == nf_id) { + break; + } + } + + if (mapIndex < MAX_CLIENTS_PER_SERVICE) { // sanity error check + services[service_id][mapIndex] = 0; + for (; mapIndex < MAX_CLIENTS_PER_SERVICE - 1; mapIndex++) { + // Shift the NULL to the end of the array + if (services[service_id][mapIndex + 1] == 0) { + // Short circuit when we reach the end of this service's list + break; + } + services[service_id][mapIndex] = services[service_id][mapIndex + 1]; + services[service_id][mapIndex + 1] = 0; + } + } + + /* Free info struct */ + /* Lookup mempool for nf_info struct */ + nf_info_mp = rte_mempool_lookup(_NF_MEMPOOL_NAME); + if (nf_info_mp == NULL) + return 1; + + rte_mempool_put(nf_info_mp, (void*)nf_info); + + return 0; +} diff --git a/onvm/onvm_mgr/onvm_nf.h b/onvm/onvm_mgr/onvm_nf.h new file mode 100644 index 000000000..06f5bcb37 --- /dev/null +++ b/onvm/onvm_mgr/onvm_nf.h @@ -0,0 +1,102 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_nf.h + + This file contains the prototypes for all functions related to packet + processing. + +******************************************************************************/ + + +#ifndef _ONVM_NF_H_ +#define _ONVM_NF_H_ + +extern uint16_t next_instance_id; + + +/********************************Interfaces***********************************/ + + +/* + * Interface checking if a given nf is "valid", meaning if it's running. + * + * Input : a pointer to the nf + * Output : a boolean answer + * + */ +inline int +onvm_nf_is_valid(struct client *cl); + + +/* + * Interface giving the smallest unsigned integer unused for a NF instance. + * + * Output : the unsigned integer + * + */ +uint16_t +onvm_nf_next_instance_id(void); + + +/* + * Interface looking through all registered NFs if one needs to start or stop. + * + */ +void +onvm_nf_check_status(void); + + +/* + * Interface giving a NF for a specific server id, depending on the flow. + * + * Inputs : the service id + a pointer to the packet whose flow help steer it. + * Output : a NF instance id + * + */ +inline uint16_t +onvm_nf_service_to_nf_map(uint16_t service_id, struct rte_mbuf *pkt); + + +#endif // _ONVM_NF_H_ diff --git a/onvm/onvm_mgr/onvm_pkt.c b/onvm/onvm_mgr/onvm_pkt.c new file mode 100644 index 000000000..8b31a8a51 --- /dev/null +++ b/onvm/onvm_mgr/onvm_pkt.c @@ -0,0 +1,396 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + onvm_pkt.c + + This file contains all functions related to receiving or + transmitting packets. + +******************************************************************************/ + + +#include "onvm_mgr.h" +#include "onvm_pkt.h" +#include "onvm_nf.h" + + + +/**********************Internal Functions Prototypes**************************/ + + +/* + * Function to send packets to one port after processing them. + * + * Input : a pointer to the tx queue + * + */ +static void +onvm_pkt_flush_port_queue(struct thread_info *tx, uint16_t port); + + +/* + * Function to send packets to one NF after processing them. + * + * Input : a pointer to the tx queue + * + */ +static void +onvm_pkt_flush_nf_queue(struct thread_info *thread, uint16_t client); + + +/* + * Function to enqueue a packet on one port's queue. + * + * Inputs : a pointer to the tx queue responsible + * the number of the port + * a pointer to the packet + * + */ +inline static void +onvm_pkt_enqueue_port(struct thread_info *tx, uint16_t port, struct rte_mbuf *buf); + + +/* + * Function to enqueue a packet on one NF's queue. + * + * Inputs : a pointer to the tx queue responsible + * the number of the port + * a pointer to the packet + * + */ +inline static void +onvm_pkt_enqueue_nf(struct thread_info *thread, uint16_t dst_service_id, struct rte_mbuf *pkt); + + +/* + * Function to process a single packet. + * + * Inputs : a pointer to the tx queue responsible + * a pointer to the packet + * a pointer to the NF involved + * + */ +inline static void +onvm_pkt_process_next_action(struct thread_info *tx, struct rte_mbuf *pkt, struct client *cl); + + +/* + * Helper function to drop a packet. + * + * Input : a pointer to the packet + * + * Ouput : an error code + * + */ +static int +onvm_pkt_drop(struct rte_mbuf *pkt); + + +/**********************************Interfaces*********************************/ + + +void +onvm_pkt_process_rx_batch(struct thread_info *rx, struct rte_mbuf *pkts[], uint16_t rx_count) { + uint16_t i; + struct onvm_pkt_meta *meta; + struct onvm_flow_entry *flow_entry; + struct onvm_service_chain *sc; + int ret; + + if (rx == NULL || pkts == NULL) + return; + + for (i = 0; i < rx_count; i++) { + meta = (struct onvm_pkt_meta*) &(((struct rte_mbuf*)pkts[i])->udata64); + meta->src = 0; + meta->chain_index = 0; + ret = onvm_flow_dir_get_pkt(pkts[i], &flow_entry); + if (ret >= 0) { + sc = flow_entry->sc; + meta->action = onvm_sc_next_action(sc, pkts[i]); + meta->destination = onvm_sc_next_destination(sc, pkts[i]); + } else { + meta->action = onvm_sc_next_action(default_chain, pkts[i]); + meta->destination = onvm_sc_next_destination(default_chain, pkts[i]); + } + /* PERF: this might hurt performance since it will cause cache + * invalidations. Ideally the data modified by the NF manager + * would be a different line than that modified/read by NFs. + * That may not be possible. + */ + + (meta->chain_index)++; + onvm_pkt_enqueue_nf(rx, meta->destination, pkts[i]); + } + + onvm_pkt_flush_all_nfs(rx); +} + + +void +onvm_pkt_process_tx_batch(struct thread_info *tx, struct rte_mbuf *pkts[], uint16_t tx_count, struct client *cl) { + uint16_t i; + struct onvm_pkt_meta *meta; + + if (tx == NULL || pkts == NULL || cl == NULL) + return; + + for (i = 0; i < tx_count; i++) { + meta = (struct onvm_pkt_meta*) &(((struct rte_mbuf*)pkts[i])->udata64); + meta->src = cl->instance_id; + if (meta->action == ONVM_NF_ACTION_DROP) { + // if the packet is drop, then is 0 + // and ! is 1. + cl->stats.act_drop += !onvm_pkt_drop(pkts[i]); + } else if (meta->action == ONVM_NF_ACTION_NEXT) { + /* TODO: Here we drop the packet : there will be a flow table + in the future to know what to do with the packet next */ + cl->stats.act_next++; + onvm_pkt_process_next_action(tx, pkts[i], cl); + } else if (meta->action == ONVM_NF_ACTION_TONF) { + cl->stats.act_tonf++; + onvm_pkt_enqueue_nf(tx, meta->destination, pkts[i]); + } else if (meta->action == ONVM_NF_ACTION_OUT) { + cl->stats.act_out++; + onvm_pkt_enqueue_port(tx, meta->destination, pkts[i]); + } else { + printf("ERROR invalid action : this shouldn't happen.\n"); + onvm_pkt_drop(pkts[i]); + return; + } + } +} + + +void +onvm_pkt_flush_all_ports(struct thread_info *tx) { + uint16_t i; + + if (tx == NULL) + return; + + for (i = 0; i < ports->num_ports; i++) + onvm_pkt_flush_port_queue(tx, i); +} + + +void +onvm_pkt_flush_all_nfs(struct thread_info *tx) { + uint16_t i; + + if (tx == NULL) + return; + + for (i = 0; i < MAX_CLIENTS; i++) + onvm_pkt_flush_nf_queue(tx, i); +} + +void +onvm_pkt_drop_batch(struct rte_mbuf **pkts, uint16_t size) { + uint16_t i; + + if (pkts == NULL) + return; + + for (i = 0; i < size; i++) + rte_pktmbuf_free(pkts[i]); +} + + +/****************************Internal functions*******************************/ + + +static void +onvm_pkt_flush_port_queue(struct thread_info *tx, uint16_t port) { + uint16_t i, sent; + volatile struct tx_stats *tx_stats; + + if (tx == NULL) + return; + + if (tx->port_tx_buf[port].count == 0) + return; + + tx_stats = &(ports->tx_stats); + sent = rte_eth_tx_burst(port, + tx->queue_id, + tx->port_tx_buf[port].buffer, + tx->port_tx_buf[port].count); + if (unlikely(sent < tx->port_tx_buf[port].count)) { + for (i = sent; i < tx->port_tx_buf[port].count; i++) { + onvm_pkt_drop(tx->port_tx_buf[port].buffer[i]); + } + tx_stats->tx_drop[port] += (tx->port_tx_buf[port].count - sent); + } + tx_stats->tx[port] += sent; + + tx->port_tx_buf[port].count = 0; +} + + +static void +onvm_pkt_flush_nf_queue(struct thread_info *thread, uint16_t client) { + uint16_t i; + struct client *cl; + + if (thread == NULL) + return; + + if (thread->nf_rx_buf[client].count == 0) + return; + + cl = &clients[client]; + + // Ensure destination NF is running and ready to receive packets + if (!onvm_nf_is_valid(cl)) + return; + + if (rte_ring_enqueue_bulk(cl->rx_q, (void **)thread->nf_rx_buf[client].buffer, + thread->nf_rx_buf[client].count) != 0) { + for (i = 0; i < thread->nf_rx_buf[client].count; i++) { + onvm_pkt_drop(thread->nf_rx_buf[client].buffer[i]); + } + cl->stats.rx_drop += thread->nf_rx_buf[client].count; + } else { + cl->stats.rx += thread->nf_rx_buf[client].count; + } + thread->nf_rx_buf[client].count = 0; +} + + +inline static void +onvm_pkt_enqueue_port(struct thread_info *tx, uint16_t port, struct rte_mbuf *buf) { + + if (tx == NULL || buf == NULL) + return; + + + tx->port_tx_buf[port].buffer[tx->port_tx_buf[port].count++] = buf; + if (tx->port_tx_buf[port].count == PACKET_READ_SIZE) { + onvm_pkt_flush_port_queue(tx, port); + } +} + + +inline static void +onvm_pkt_enqueue_nf(struct thread_info *thread, uint16_t dst_service_id, struct rte_mbuf *pkt) { + struct client *cl; + uint16_t dst_instance_id; + + + if (thread == NULL || pkt == NULL) + return; + + // map service to instance and check one exists + dst_instance_id = onvm_nf_service_to_nf_map(dst_service_id, pkt); + if (dst_instance_id == 0) { + onvm_pkt_drop(pkt); + return; + } + + // Ensure destination NF is running and ready to receive packets + cl = &clients[dst_instance_id]; + if (!onvm_nf_is_valid(cl)) { + onvm_pkt_drop(pkt); + return; + } + + thread->nf_rx_buf[dst_instance_id].buffer[thread->nf_rx_buf[dst_instance_id].count++] = pkt; + if (thread->nf_rx_buf[dst_instance_id].count == PACKET_READ_SIZE) { + onvm_pkt_flush_nf_queue(thread, dst_instance_id); + } +} + + +inline static void +onvm_pkt_process_next_action(struct thread_info *tx, struct rte_mbuf *pkt, struct client *cl) { + + if (tx == NULL || pkt == NULL || cl == NULL) + return; + + struct onvm_flow_entry *flow_entry; + struct onvm_service_chain *sc; + struct onvm_pkt_meta *meta = onvm_get_pkt_meta(pkt); + int ret; + + ret = onvm_flow_dir_get_pkt(pkt, &flow_entry); + if (ret >= 0) { + sc = flow_entry->sc; + meta->action = onvm_sc_next_action(sc, pkt); + meta->destination = onvm_sc_next_destination(sc, pkt); + } else { + meta->action = onvm_sc_next_action(default_chain, pkt); + meta->destination = onvm_sc_next_destination(default_chain, pkt); + } + + switch (meta->action) { + case ONVM_NF_ACTION_DROP: + // if the packet is drop, then is 0 + // and ! is 1. + cl->stats.act_drop += !onvm_pkt_drop(pkt); + break; + case ONVM_NF_ACTION_TONF: + cl->stats.act_tonf++; + onvm_pkt_enqueue_nf(tx, meta->destination, pkt); + break; + case ONVM_NF_ACTION_OUT: + cl->stats.act_out++; + onvm_pkt_enqueue_port(tx, meta->destination, pkt); + break; + default: + break; + } + (meta->chain_index)++; +} + + +/*******************************Helper function*******************************/ + + +static int +onvm_pkt_drop(struct rte_mbuf *pkt) { + rte_pktmbuf_free(pkt); + if (pkt != NULL) { + return 1; + } + return 0; +} diff --git a/onvm/onvm_mgr/onvm_pkt.h b/onvm/onvm_mgr/onvm_pkt.h new file mode 100644 index 000000000..b6aacfbfd --- /dev/null +++ b/onvm/onvm_mgr/onvm_pkt.h @@ -0,0 +1,116 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_pkt.h + + + Header file containing all prototypes of packet processing functions + + +******************************************************************************/ + + +#ifndef _ONVM_PKT_H_ +#define _ONVM_PKT_H_ + + +/*********************************Interfaces**********************************/ + + +/* + * Interface to process packets in a given RX queue. + * + * Inputs : a pointer to the rx queue + * an array of packets + * the size of the array + * + */ +void +onvm_pkt_process_rx_batch(struct thread_info *rx, struct rte_mbuf *pkts[], uint16_t rx_count); + + +/* + * Interface to process packets in a given TX queue. + * + * Inputs : a pointer to the tx queue + * an array of packets + * the size of the array + * a pointer to the client possessing the TX queue. + * + */ +void +onvm_pkt_process_tx_batch(struct thread_info *tx, struct rte_mbuf *pkts[], uint16_t tx_count, struct client *cl); + + +/* + * Interface to send packets to all ports after processing them. + * + * Input : a pointer to the tx queue + * + */ +void +onvm_pkt_flush_all_ports(struct thread_info *tx); + + +/* + * Interface to send packets to all NFs after processing them. + * + * Input : a pointer to the tx queue + * + */ +void +onvm_pkt_flush_all_nfs(struct thread_info *tx); + + +/* + * Interface to drop a batch of packets. + * + * Inputs : the array of packets + * the size of the array + * + */ +void +onvm_pkt_drop_batch(struct rte_mbuf **pkts, uint16_t size); + + +#endif // _ONVM_PKT_H_ diff --git a/onvm/onvm_mgr/onvm_stats.c b/onvm/onvm_mgr/onvm_stats.c new file mode 100644 index 000000000..db399f532 --- /dev/null +++ b/onvm/onvm_mgr/onvm_stats.c @@ -0,0 +1,219 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + onvm_stats.c + + This file contain the implementation of all functions related to + statistics display in the manager. + +******************************************************************************/ + + +#include "onvm_mgr.h" +#include "onvm_stats.h" +#include "onvm_nf.h" + + +/************************Internal Functions Prototypes************************/ + + +/* + * Function displaying statistics for all ports + * + * Input : time passed since last display (to compute packet rate) + * + */ +static void +onvm_stats_display_ports(unsigned difftime); + + +/* + * Function displaying statistics for all clients + * + */ +static void +onvm_stats_display_clients(void); + + +/* + * Function clearing the terminal and moving back the cursor to the top left. + * + */ +static void +onvm_stats_clear_terminal(void); + + +/* + * Function giving the MAC address of a port in string format. + * + * Input : port + * Output : its MAC address + * + */ +static const char * +onvm_stats_print_MAC(uint8_t port); + + +/****************************Interfaces***************************************/ + + +void +onvm_stats_display_all(unsigned difftime) { + onvm_stats_clear_terminal(); + onvm_stats_display_ports(difftime); + onvm_stats_display_clients(); +} + + +void +onvm_stats_clear_all_clients(void) { + unsigned i; + + for (i = 0; i < MAX_CLIENTS; i++) { + clients[i].stats.rx = clients[i].stats.rx_drop = 0; + clients[i].stats.act_drop = clients[i].stats.act_tonf = 0; + clients[i].stats.act_next = clients[i].stats.act_out = 0; + } +} + +void +onvm_stats_clear_client(uint16_t id) { + clients[id].stats.rx = clients[id].stats.rx_drop = 0; + clients[id].stats.act_drop = clients[id].stats.act_tonf = 0; + clients[id].stats.act_next = clients[id].stats.act_out = 0; +} + + +/****************************Internal functions*******************************/ + + +static void +onvm_stats_display_ports(unsigned difftime) { + unsigned i; + /* Arrays to store last TX/RX count to calculate rate */ + static uint64_t tx_last[RTE_MAX_ETHPORTS]; + static uint64_t rx_last[RTE_MAX_ETHPORTS]; + + printf("PORTS\n"); + printf("-----\n"); + for (i = 0; i < ports->num_ports; i++) + printf("Port %u: '%s'\t", (unsigned)ports->id[i], + onvm_stats_print_MAC(ports->id[i])); + printf("\n\n"); + for (i = 0; i < ports->num_ports; i++) { + printf("Port %u - rx: %9"PRIu64" (%9"PRIu64" pps)\t" + "tx: %9"PRIu64" (%9"PRIu64" pps)\n", + (unsigned)ports->id[i], + ports->rx_stats.rx[ports->id[i]], + (ports->rx_stats.rx[ports->id[i]] - rx_last[i]) + /difftime, + ports->tx_stats.tx[ports->id[i]], + (ports->tx_stats.tx[ports->id[i]] - tx_last[i]) + /difftime); + + rx_last[i] = ports->rx_stats.rx[ports->id[i]]; + tx_last[i] = ports->tx_stats.tx[ports->id[i]]; + } +} + + +static void +onvm_stats_display_clients(void) { + unsigned i; + + printf("\nCLIENTS\n"); + printf("-------\n"); + for (i = 0; i < MAX_CLIENTS; i++) { + if (!onvm_nf_is_valid(&clients[i])) + continue; + const uint64_t rx = clients[i].stats.rx; + const uint64_t rx_drop = clients[i].stats.rx_drop; + const uint64_t tx = clients_stats->tx[i]; + const uint64_t tx_drop = clients_stats->tx_drop[i]; + const uint64_t act_drop = clients[i].stats.act_drop; + const uint64_t act_next = clients[i].stats.act_next; + const uint64_t act_out = clients[i].stats.act_out; + const uint64_t act_tonf = clients[i].stats.act_tonf; + const uint64_t act_buffer = clients_stats->tx_buffer[i]; + const uint64_t act_returned = clients_stats->tx_returned[i]; + + printf("Client %2u - rx: %9"PRIu64" rx_drop: %9"PRIu64" next: %9"PRIu64" drop: %9"PRIu64" ret: %9"PRIu64"\n" + "tx: %9"PRIu64" tx_drop: %9"PRIu64" out: %9"PRIu64" tonf: %9"PRIu64" buf: %9"PRIu64"\n", + clients[i].info->instance_id, + rx, rx_drop, act_next, act_drop, act_returned, + tx, tx_drop, act_out, act_tonf, act_buffer); + } + + printf("\n"); +} + + +/***************************Helper functions**********************************/ + + +static void +onvm_stats_clear_terminal(void) { + const char clr[] = { 27, '[', '2', 'J', '\0' }; + const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; + + printf("%s%s", clr, topLeft); +} + + +static const char * +onvm_stats_print_MAC(uint8_t port) { + static const char err_address[] = "00:00:00:00:00:00"; + static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)]; + + if (unlikely(port >= RTE_MAX_ETHPORTS)) + return err_address; + if (unlikely(addresses[port][0] == '\0')) { + struct ether_addr mac; + rte_eth_macaddr_get(port, &mac); + snprintf(addresses[port], sizeof(addresses[port]), + "%02x:%02x:%02x:%02x:%02x:%02x\n", + mac.addr_bytes[0], mac.addr_bytes[1], + mac.addr_bytes[2], mac.addr_bytes[3], + mac.addr_bytes[4], mac.addr_bytes[5]); + } + return addresses[port]; +} diff --git a/onvm/onvm_mgr/onvm_stats.h b/onvm/onvm_mgr/onvm_stats.h new file mode 100644 index 000000000..0493cac57 --- /dev/null +++ b/onvm/onvm_mgr/onvm_stats.h @@ -0,0 +1,89 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + onvm_stats.h + + This file contains all function prototypes related to + statistics display. + +******************************************************************************/ + + +#ifndef _ONVM_STATS_H_ +#define _ONVM_STATS_H_ + + +/*********************************Interfaces**********************************/ + + +/* + * Interface called by the ONVM Manager to display all statistics + * available. + * + * Input : time passed since last display (to compute packet rate) + * + */ +void onvm_stats_display_all(unsigned difftime); + + +/* + * Interface called by the ONVM Manager to clear all clients statistics + * available. + * + * Note : this function doesn't use onvm_stats_clear_client for each client, + * since with a huge number of clients, the additional functions calls would + * incur a visible slowdown. + * + */ +void onvm_stats_clear_all_clients(void); + + +/* + * Interface called by the ONVM Manager to clear one client's statistics. + * + * Input : the client id + * + */ +void onvm_stats_clear_client(uint16_t id); + + +#endif // _ONVM_STATS_H_ diff --git a/onvm/onvm_nf/Makefile b/onvm/onvm_nflib/Makefile similarity index 100% rename from onvm/onvm_nf/Makefile rename to onvm/onvm_nflib/Makefile diff --git a/onvm/onvm_nf/onvm_nflib.c b/onvm/onvm_nflib/onvm_nflib.c similarity index 80% rename from onvm/onvm_nf/onvm_nflib.c rename to onvm/onvm_nflib/onvm_nflib.c index 485573e0a..b5f5dc58e 100644 --- a/onvm/onvm_nf/onvm_nflib.c +++ b/onvm/onvm_nflib/onvm_nflib.c @@ -35,182 +35,131 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * onvm_nflib.c - client lib NF for simple onvm ********************************************************************/ -#include -#include -#include -#include -#include -#include -#include +/****************************************************************************** + + onvm_nflib.c + + + File containing all functions of the NF API + + +******************************************************************************/ + + +/***************************Standard C library********************************/ + + #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" + + +/*****************************Internal headers********************************/ + + #include "onvm_nflib.h" +#include "onvm_includes.h" #include "onvm_sc_common.h" -/* Number of packets to attempt to read from queue */ -#define PKT_READ_SIZE ((uint16_t)32) -/* ring used to place new nf_info struct */ +/**********************************Macros*************************************/ + + +// Number of packets to attempt to read from queue +#define PKT_READ_SIZE ((uint16_t)32) + + +/******************************Global Variables*******************************/ + + +// ring used to place new nf_info struct static struct rte_ring *nf_info_ring; -/* rings used to pass packets between NFlib and NFmgr */ + +// rings used to pass packets between NFlib and NFmgr static struct rte_ring *tx_ring, *rx_ring; -/* shared data from server. We update statistics here */ + +// shared data from server. We update statistics here static volatile struct client_tx_stats *tx_stats; -/* Shared data for client info */ + +// Shared data for client info extern struct onvm_nf_info *nf_info; -/* Shared pool for all clients info */ + +// Shared pool for all clients info static struct rte_mempool *nf_info_mp; -/* User-given NF Client ID (defaults to manager assigned) */ + +// User-given NF Client ID (defaults to manager assigned) static uint16_t initial_instance_id = NF_NO_ID; -/* User supplied service ID */ + +// User supplied service ID static uint16_t service_id = -1; -/* True as long as the NF should keep processing packets */ + +// True as long as the NF should keep processing packets static uint8_t keep_running = 1; -/* Shared data for default service chain*/ + +// Shared data for default service chain static struct onvm_service_chain *default_chain; + +/***********************Internal Functions Prototypes*************************/ + + /* - * Print a usage message + * Function that initialize a nf info data structure. + * + * Input : the tag to name the NF + * Output : the data structure initialized + * */ -static void -usage(const char *progname) { - printf("Usage: %s [EAL args] -- " -#ifdef USE_STATIC_IDS - "[-n ]" -#endif - "[-r ]\n\n", progname); -} +static struct onvm_nf_info * +onvm_nflib_info_init(const char *tag); + /* - * Parse the library arguments. + * Function printing an explanation of command line instruction for a NF. + * + * Input : name of the executable containing the NF + * */ -static int -parse_nflib_args(int argc, char *argv[]) { - const char *progname = argv[0]; - int c; - - opterr = 0; -#ifdef USE_STATIC_IDS - while ((c = getopt (argc, argv, "n:r:")) != -1) -#else - while ((c = getopt (argc, argv, "r:")) != -1) -#endif - switch (c) { -#ifdef USE_STATIC_IDS - case 'n': - initial_instance_id = (uint16_t) strtoul(optarg, NULL, 10); - break; -#endif - case 'r': - service_id = (uint16_t) strtoul(optarg, NULL, 10); - // Service id 0 is reserved - if (service_id == 0) service_id = -1; - break; - case '?': - usage(progname); - if (optopt == 'n') - fprintf(stderr, "Option -%c requires an argument.\n", optopt); - else if (isprint(optopt)) - fprintf(stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); - return -1; - default: - return -1; - } +static void +onvm_nflib_usage(const char *progname); - if (service_id == (uint16_t)-1) { - /* Service ID is required */ - fprintf(stderr, "You must provide a nonzero service ID with -r\n"); - return -1; - } - return optind; -} -/** - * CALLED BY NF: - * Create a new nf_info struct for this NF - * Pass a unique tag for this NF +/* + * Function that parses the global arguments common to all NFs. + * + * Input : the number of arguments (following C standard library convention) + * an array of strings representing these arguments + * Output : an error code + * */ -static struct onvm_nf_info * -ovnm_nf_info_init(const char *tag) -{ - void *mempool_data; - struct onvm_nf_info *info; +static int +onvm_nflib_parse_args(int argc, char *argv[]); - if (rte_mempool_get(nf_info_mp, &mempool_data) < 0) { - rte_exit(EXIT_FAILURE, "Failed to get client info memory"); - } - if (mempool_data == NULL) { - rte_exit(EXIT_FAILURE, "Client Info struct not allocated"); - } +/* +* Signal handler to catch SIGINT. +* +* Input : int corresponding to the signal catched +* +*/ +static void +onvm_nflib_handle_signal(int sig); - info = (struct onvm_nf_info*) mempool_data; - info->instance_id = initial_instance_id; - info->service_id = service_id; - info->status = NF_WAITING_FOR_ID; - info->tag = tag; - return info; -} +/************************************API**************************************/ -/** - * CALLED BY NF: - * Sets this NF to not runnings and exits with EXIT_SUCCESS - */ -void -onvm_nf_stop(void) { - rte_exit(EXIT_SUCCESS, "Done."); -} -/** - * CALLED BY NF: - * Initialises everything we need - * - * Returns the number of arguments parsed by both rte_eal_init and - * parse_nflib_args offset by 1. This is used by getopt in the NF's - * code. The offsetting by one accounts for getopt parsing "--" which - * increments optind by 1 each time. - */ int -onvm_nf_init(int argc, char *argv[], const char *nf_tag) { +onvm_nflib_init(int argc, char *argv[], const char *nf_tag) { const struct rte_memzone *mz; const struct rte_memzone *mz_scp; struct rte_mempool *mp; @@ -226,7 +175,7 @@ onvm_nf_init(int argc, char *argv[], const char *nf_tag) { /* Reset getopt global variables opterr and optind to their default values */ opterr = 0; optind = 1; - if ((retval_parse = parse_nflib_args(argc, argv)) < 0) + if ((retval_parse = onvm_nflib_parse_args(argc, argv)) < 0) rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); /* @@ -248,7 +197,7 @@ onvm_nf_init(int argc, char *argv[], const char *nf_tag) { rte_exit(EXIT_FAILURE, "No Client Info mempool - bye\n"); /* Initialize the info struct */ - nf_info = ovnm_nf_info_init(nf_tag); + nf_info = onvm_nflib_info_init(nf_tag); mp = rte_mempool_lookup(PKTMBUF_POOL_NAME); if (mp == NULL) @@ -313,24 +262,12 @@ onvm_nf_init(int argc, char *argv[], const char *nf_tag) { return retval_final; } -/** - * Called for SIGINT, or ^C - * Tells the main loop it's time to exit and clean up - */ -static void -handle_signal(int sig) -{ - if (sig == SIGINT) - keep_running = 0; -} -/** - * CALLED BY NF: - * Application main function - loops through - * receiving and processing packets. Never returns - */ int -onvm_nf_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struct onvm_pkt_meta* meta)) { +onvm_nflib_run( + struct onvm_nf_info* info, + int(*handler)(struct rte_mbuf* pkt, struct onvm_pkt_meta* meta) + ) { void *pkts[PKT_READ_SIZE]; struct onvm_pkt_meta* meta; @@ -338,7 +275,7 @@ onvm_nf_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struc printf("[Press Ctrl-C to quit ...]\n"); /* Listen for ^C so we can exit gracefully */ - signal(SIGINT, handle_signal); + signal(SIGINT, onvm_nflib_handle_signal); for (; keep_running;) { uint16_t i, j, nb_pkts = PKT_READ_SIZE; @@ -394,11 +331,9 @@ onvm_nf_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struc return 0; } -/* - * Return a buffered packet. - */ + int -onvm_nf_return_pkt(struct rte_mbuf* pkt) { +onvm_nflib_return_pkt(struct rte_mbuf* pkt) { /* FIXME: should we get a batch of buffered packets and then enqueue? Can we keep stats? */ if(unlikely(rte_ring_enqueue(tx_ring, pkt) == -ENOBUFS)) { rte_pktmbuf_free(pkt); @@ -408,3 +343,98 @@ onvm_nf_return_pkt(struct rte_mbuf* pkt) { else tx_stats->tx_returned[nf_info->instance_id]++; return 0; } + + +void +onvm_nflib_stop(void) { + rte_exit(EXIT_SUCCESS, "Done."); +} + + +/******************************Helper functions*******************************/ + + +static struct onvm_nf_info * +onvm_nflib_info_init(const char *tag) +{ + void *mempool_data; + struct onvm_nf_info *info; + + if (rte_mempool_get(nf_info_mp, &mempool_data) < 0) { + rte_exit(EXIT_FAILURE, "Failed to get client info memory"); + } + + if (mempool_data == NULL) { + rte_exit(EXIT_FAILURE, "Client Info struct not allocated"); + } + + info = (struct onvm_nf_info*) mempool_data; + info->instance_id = initial_instance_id; + info->service_id = service_id; + info->status = NF_WAITING_FOR_ID; + info->tag = tag; + + return info; +} + + +static void +onvm_nflib_usage(const char *progname) { + printf("Usage: %s [EAL args] -- " +#ifdef USE_STATIC_IDS + "[-n ]" +#endif + "[-r ]\n\n", progname); +} + + +static int +onvm_nflib_parse_args(int argc, char *argv[]) { + const char *progname = argv[0]; + int c; + + opterr = 0; +#ifdef USE_STATIC_IDS + while ((c = getopt (argc, argv, "n:r:")) != -1) +#else + while ((c = getopt (argc, argv, "r:")) != -1) +#endif + switch (c) { +#ifdef USE_STATIC_IDS + case 'n': + initial_instance_id = (uint16_t) strtoul(optarg, NULL, 10); + break; +#endif + case 'r': + service_id = (uint16_t) strtoul(optarg, NULL, 10); + // Service id 0 is reserved + if (service_id == 0) service_id = -1; + break; + case '?': + onvm_nflib_usage(progname); + if (optopt == 'n') + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + return -1; + default: + return -1; + } + + if (service_id == (uint16_t)-1) { + /* Service ID is required */ + fprintf(stderr, "You must provide a nonzero service ID with -r\n"); + return -1; + } + return optind; +} + + +static void +onvm_nflib_handle_signal(int sig) +{ + if (sig == SIGINT) + keep_running = 0; +} diff --git a/onvm/onvm_nf/onvm_nflib.h b/onvm/onvm_nflib/onvm_nflib.h similarity index 83% rename from onvm/onvm_nf/onvm_nflib.h rename to onvm/onvm_nflib/onvm_nflib.h index 6687503da..c5da75ccc 100644 --- a/onvm/onvm_nf/onvm_nflib.h +++ b/onvm/onvm_nflib/onvm_nflib.h @@ -35,34 +35,26 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * onvm_nflib.h - client lib NF for simple onvm ********************************************************************/ + +/****************************************************************************** + + onvm_nflib.h + + + Header file for the API + + +******************************************************************************/ + + #ifndef _ONVM_NFLIB_H_ #define _ONVM_NFLIB_H_ #include #include "common.h" -/** - * Initialize a NF Info Struct. - * Allocates and returns a pointer to a struct that defines information - * about a new NF. - * - * @param tag - * A buffer containing a uniquely-identifiable tag for this NF. - * For example, can be the application name (e.g. "bridge_nf") - * @return - * On success, a pointer to the created info struct. Will exit on error - */ -struct onvm_nf_info * -onvm_nf_info_init(const char *tag); - -/** - * Stop this NF - * Sets the info to be not running and exits this process gracefully - */ -void -onvm_nf_stop(void); +/************************************API**************************************/ /** * Initialize the OpenNetVM container Library. @@ -83,7 +75,7 @@ onvm_nf_stop(void); * On error, a negative value . */ int -onvm_nf_init(int argc, char *argv[], const char *nf_tag); +onvm_nflib_init(int argc, char *argv[], const char *nf_tag); /** @@ -99,7 +91,8 @@ onvm_nf_init(int argc, char *argv[], const char *nf_tag); * 0 on success, or a negative value on error. */ int -onvm_nf_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struct onvm_pkt_meta* action)); +onvm_nflib_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struct onvm_pkt_meta* action)); + /** * Return a packet that has previously had the ONVM_NF_ACTION_BUFFER action @@ -111,6 +104,15 @@ onvm_nf_run(struct onvm_nf_info* info, int(*handler)(struct rte_mbuf* pkt, struc * 0 on success, or a negative value on error. */ int -onvm_nf_return_pkt(struct rte_mbuf* pkt); +onvm_nflib_return_pkt(struct rte_mbuf* pkt); + + +/** + * Stop this NF + * Sets the info to be not running and exits this process gracefully + */ +void +onvm_nflib_stop(void); + -#endif +#endif // _ONVM_NFLIB_H_ diff --git a/onvm/onvm_nflib/onvm_nflib_internal.h b/onvm/onvm_nflib/onvm_nflib_internal.h new file mode 100644 index 000000000..377f530a8 --- /dev/null +++ b/onvm/onvm_nflib/onvm_nflib_internal.h @@ -0,0 +1,162 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * 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. + * * 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_nflib_internal.h + + + Header file for all internal functions used within the API + + +******************************************************************************/ + + +#ifndef _ONVM_NFLIB_INTERNAL_H_ +#define _ONVM_NFLIB_INTERNAL_H_ + + +/***************************Standard C library********************************/ + + +#include +#include + + +/*****************************Internal headers********************************/ + + +#include "onvm_includes.h" +#include "onvm_sc_common.h" + + +/**********************************Macros*************************************/ + + +// Number of packets to attempt to read from queue +#define PKT_READ_SIZE ((uint16_t)32) + + +/******************************Global Variables*******************************/ + + +// ring used to place new nf_info struct +static struct rte_ring *nf_info_ring; + + +// rings used to pass packets between NFlib and NFmgr +static struct rte_ring *tx_ring, *rx_ring; + + +// shared data from server. We update statistics here +static volatile struct client_tx_stats *tx_stats; + + +// Shared data for client info +extern struct onvm_nf_info *nf_info; + + +// Shared pool for all clients info +static struct rte_mempool *nf_info_mp; + + +// User-given NF Client ID (defaults to manager assigned) +static uint16_t initial_instance_id = NF_NO_ID; + + +// User supplied service ID +static uint16_t service_id = -1; + + +// True as long as the NF should keep processing packets +static uint8_t keep_running = 1; + + +// Shared data for default service chain +static struct onvm_service_chain *default_chain; + + +/******************************Internal functions*****************************/ + + +/* + * Function that initialize a nf info data structure. + * + * Input : the tag to name the NF + * Output : the data structure initialized + * + */ +static struct onvm_nf_info * +onvm_nflib_info_init(const char *tag); + + +/* + * Function printing an explanation of command line instruction for a NF. + * + * Input : name of the executable containing the NF + * + */ +static void +onvm_nflib_usage(const char *progname); + + +/* + * Function that parses the global arguments common to all NFs. + * + * Input : the number of arguments (following C standard library convention) + * an array of strings representing these arguments + * Output : an error code + * + */ +static int +onvm_nflib_parse_args(int argc, char *argv[]); + + +/* + * Signal handler to catch SIGINT. + * + * Input : int corresponding to the signal catched + * + */ +static void +onvm_nflib_handle_signal(int sig); + + +#endif // _ONVM_NFLIB_INTERNAL_H_ diff --git a/onvm/shared/onvm_includes.h b/onvm/shared/onvm_includes.h new file mode 100644 index 000000000..d1c94ed8e --- /dev/null +++ b/onvm/shared/onvm_includes.h @@ -0,0 +1,101 @@ +/********************************************************************* + * openNetVM + * https://sdnfv.github.io + * + * BSD LICENSE + * + * Copyright(c) + * 2015-2016 George Washington University + * 2015-2016 University of California Riverside + * 2010-2014 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. + * + ********************************************************************/ + + +/****************************************************************************** + + onvm_includes.h + + + Header file containing all shared headers and data structures + + +******************************************************************************/ + + +#ifndef _ONVM_INCLUDES_H_ +#define _ONVM_INCLUDES_H_ + + +/******************************Standard C library*****************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/********************************DPDK library*********************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************Internal headers*******************************/ + + +#include "common.h" + +#endif // _ONVM_INCLUDES_H_