summaryrefslogtreecommitdiffstats
path: root/common/vnf_common/rest_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/vnf_common/rest_api.c')
-rw-r--r--common/vnf_common/rest_api.c2448
1 files changed, 2448 insertions, 0 deletions
diff --git a/common/vnf_common/rest_api.c b/common/vnf_common/rest_api.c
new file mode 100644
index 00000000..62e9646a
--- /dev/null
+++ b/common/vnf_common/rest_api.c
@@ -0,0 +1,2448 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_hash.h>
+#include <rte_ethdev.h>
+#include <rte_cycles.h>
+#include <rte_timer.h>
+#include <rte_debug.h>
+#include <rte_cfgfile.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "pipeline_common_fe.h"
+#include "pipeline_arpicmp.h"
+
+#include <civetweb.h>
+#include <json/json.h>
+#include "app.h"
+#include "lib_arp.h"
+#include "interface.h"
+#include "tsx.h"
+#include "gateway.h"
+
+#define MAX_PIPELINES 30
+#define MAX_VNFS 3
+#define CFG_NAME_LEN 64
+#define MAX_CORES 64
+#define MAX_SOCKET 2
+#define MAX_BUF_SIZE 2048
+#define MAX_SIZE 24
+#define MAX_LINKS 64
+#define MAX_LB 20
+#define msleep(x) rte_delay_us(x * 1000)
+
+const char *pipelines[9] = {"MASTER", "ARPICMP", "TIMER", "TXRX-BEGIN",
+ "TXRX-END", "LOADB", "VACL", "VCGNAPT", "VFW"};
+const char *VNFS[] = {"VACL", "VCGNAPT", "VFW"};
+struct mg_context *ctx;
+struct pub_ip_range {
+ char value[MAX_BUF_SIZE];
+};
+
+struct stat_cfg {
+ uint8_t num_workers;
+ uint8_t num_lb;
+ uint8_t num_ports;
+ uint8_t hyper_thread;
+ uint8_t sock_in;
+ uint8_t sw_lb;
+ char vnf_type[MAX_SIZE];
+ char pkt_type[MAX_SIZE];
+ char pci_white_list[MAX_BUF_SIZE];
+ struct pub_ip_range ip_range[MAX_LB];
+};
+
+struct arp_params {
+ uint8_t family;
+ uint8_t action;
+ union {
+ uint32_t ip;
+ uint8_t ipv6[16];
+ };
+ uint32_t portid;
+ struct ether_addr mac_addr;
+};
+
+struct link_params {
+ uint32_t id;
+ uint32_t state;
+ union {
+ uint32_t ip;
+ uint8_t ipv6[16];
+ };
+ uint32_t depth;
+ uint32_t family;
+};
+
+struct route_params {
+ uint32_t enable;
+ union {
+ uint32_t ip;
+ uint8_t ipv6[16];
+ };
+ uint32_t depth;
+ uint32_t family;
+ char type[255];
+};
+
+struct dbg_mode {
+ uint32_t cmd;
+ uint32_t d1;
+ uint32_t pipe_num;
+};
+
+struct dbg_mode current_dbg;
+struct link_params current_link_parms[MAX_LINKS];
+struct stat_cfg current_cfg;
+struct arp_params current_arp_parms;
+struct route_params current_route_parms[MAX_LINKS];
+
+static int static_cfg_set = 0;
+uint8_t pipe_arr[MAX_PIPELINES];
+uint8_t num_pipelines;
+uint8_t num_workers, pub_ip = 0, ip_range = 0, num_lb = 1, num_ports;
+uint8_t num_entries, start_lb, end_lb, start_lbout;
+uint8_t swq_index = 0, workers = 0;
+uint8_t txq_index = 0, sw_lb = 1;
+uint8_t rxq_index = 0;
+uint8_t arp_index = 0, tx_start_port = 0, rx_start_port = 0;
+uint8_t pipenum = 0, hyper_thread = 0;
+char traffic_type[4] = "4";
+struct rte_cfgfile_entry entries[30];
+int n_entries1 = 0;
+char loadb_in[256];
+char vnf_type[256];
+uint8_t sock_cpus[MAX_SOCKET][MAX_CORES];
+uint8_t sock_in = 0, sock0 = 0, sock1 = 0, sock_index = 0;
+int hyper = 0;
+uint32_t flow_dir_cfg = 0;
+struct app_params *rapp;
+
+extern uint32_t nd_route_tbl_index;
+extern struct arp_data *p_arp_data;
+extern int USE_RTM_LOCKS;
+extern rte_rwlock_t rwlock;
+extern interface_main_t ifm;
+extern struct cmdline *pipe_cl;
+extern uint16_t str2flowtype(char *string);
+extern void app_run_file(cmdline_parse_ctx_t *ctx, const char *file_name);
+extern int parse_flexbytes(const char *q_arg, uint8_t *flexbytes,
+ uint16_t max_num);
+extern int app_pipeline_arpicmp_entry_dbg(struct app_params *app,
+ uint32_t pipeline_id, uint8_t *msg);
+extern unsigned eal_cpu_socket_id(unsigned cpu_id);
+extern int app_routeadd_config_ipv4(__attribute__((unused))
+ struct app_params *app,
+ uint32_t port_id, uint32_t ip,
+ uint32_t mask);
+extern int app_routeadd_config_ipv6(__attribute__((unused))
+ struct app_params *app,
+ uint32_t port_id, uint8_t ipv6[],
+ uint32_t depth);
+
+enum rte_eth_input_set_field str2inset(char *string);
+
+enum {
+ MASTER = 0,
+ ARPICMP,
+ TIMER,
+ TXRX_BEGIN,
+ TXRX_END,
+ LOADB,
+ VNF_VACL,
+ VNF_VCGNAPT,
+ VNF_VFW,
+ PIPE_MAX
+};
+
+struct json_data {
+ char key[256];
+ char value[256];
+};
+
+struct json_data static_cfg[40];
+uint32_t post_not_received = 1;
+
+int flow_director_handler(struct mg_connection *conn,
+ __rte_unused void *cbdata);
+int vnf_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+void init_stat_cfg(void);
+void bind_the_ports(struct mg_connection *conn, char *pci_white_list);
+int route_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int dbg_pipelines_handler(struct mg_connection *conn,
+ __rte_unused void *cbdata);
+int dbg_pipelines_id_handler(struct mg_connection *conn,
+ __rte_unused void *cbdata);
+int get_pipelines_tokens(char *buf);
+void get_swq_offset(uint8_t start, uint8_t num, char *buf);
+void get_swq(uint8_t num, char *buf);
+void get_txq(uint8_t start_q, uint8_t queue_num, uint8_t ports, char *buf);
+void get_rxq(uint8_t start_q, uint8_t queue_num, uint8_t ports, char *buf);
+void fix_pipelines_data_types(FILE *f, const char *sect_name,
+ struct rte_cfgfile *tcfg);
+void print_to_file(FILE *f, struct rte_cfgfile *tcfg);
+int get_vnf_index(void);
+void build_pipeline(void);
+void get_pktq_in_prv(char *buf);
+void get_prv_to_pub_map(char *buf);
+void get_prv_que_handler(char *buf);
+int static_cfg_handler(struct mg_connection *conn, void *cbdata);
+int link_handler(struct mg_connection *conn, void *cbdata);
+int linkid_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int arp_handler(struct mg_connection *conn, void *cbdata);
+int arpls_handler(struct mg_connection *conn, void *cbdata);
+int nd_handler(struct mg_connection *conn, void *cbdata);
+int linkls_handler(struct mg_connection *conn, void *cbdata);
+int set_hash_input_set_2(struct mg_connection *conn, uint32_t port_id,
+ const char *flow_type, const char *inset_field0,
+ const char *inset_field1, const char *select);
+int set_hash_input_set_4(struct mg_connection *conn, uint32_t port_id,
+ char *flow_type, char *inset_field0, char *inset_field1,
+ char *inset_field2, char *inset_field3, const char *select);
+int set_hash_global_config(struct mg_connection *conn, uint32_t port_id,
+ char *flow_type, const char *hash_func, const char *enable);
+int set_sym_hash_per_port(struct mg_connection *conn, uint32_t port_id);
+int cmd_quit_handler(struct mg_connection *conn, void *cbdata);
+int dbg_run_handler(struct mg_connection *conn, void *cbdata);
+int dbg_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int dbg_cmd_handler(struct mg_connection *conn, void *cbdata);
+int run_field_found(const char *key, const char *filename, char *path,
+ size_t pathlen, void *user_data);
+int run_field_get(const char *key, const char *value, size_t valuelen,
+ void *user_data);
+int run_field_stored(const char *path, long long file_size, void *user_data);
+void print_interface_details_rest(struct mg_connection *conn, uint32_t link);
+void print_link_info(struct app_link_params *p, struct mg_connection *conn);
+int get_link_tokens(char *buf);
+void get_mac(struct ether_addr *mac_addr, char *buf);
+
+int run_field_found(const char *key, const char *filename, char *path,
+ size_t pathlen, void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+
+ mg_printf(conn, "\r\n\r\n%s:\r\n", key);
+
+ if (filename && *filename) {
+ snprintf(path, pathlen, "%s", filename);
+ int fd;
+
+ /* Make sure file exists before clearing rules and actions */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ mg_printf(conn, "Cannot open file \"%s\"\n", filename);
+ return FORM_FIELD_STORAGE_GET;
+ }
+
+ close(fd);
+ mg_printf(conn, "file to be loaded is %s\n", filename);
+ app_run_file(pipe_cl->ctx, filename);
+
+ return FORM_FIELD_STORAGE_STORE;
+ }
+
+ return FORM_FIELD_STORAGE_GET;
+}
+
+int run_field_get(const char *key, const char *value, size_t valuelen,
+ void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+
+ if (key[0]) {
+ mg_printf(conn, "%s = ", key);
+ }
+ mg_write(conn, value, valuelen);
+
+ return 0;
+}
+
+int run_field_stored(const char *path, long long file_size, void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+
+ mg_printf(conn,
+ "stored as %s (%lu bytes)\r\n\r\n",
+ path,
+ (unsigned long)file_size);
+
+ return 0;
+}
+
+int dbg_run_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ struct mg_form_data_handler fdh = {run_field_found, run_field_get,
+ run_field_stored, NULL};
+
+ if (strcmp(req_info->request_method, "POST")) {
+
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection:");
+ mg_printf(conn," close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+
+ /* It would be possible to check the request info here before calling
+ * mg_handle_form_request. */
+ (void)req_info;
+
+ mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: ");
+ mg_printf(conn, "text/plain\r\nConnection: close\r\n\r\n");
+ if (strcmp(req_info->request_method, "PUT")) {
+ mg_printf(conn, "Only PUT method allowed");
+ return 1;
+ }
+
+ fdh.user_data = (void *)conn;
+
+ /* Call the form handler */
+ mg_handle_form_request(conn, &fdh);
+ mg_printf(conn, "\r\n script file handled");
+
+ return 1;
+}
+
+int cmd_quit_handler(__rte_unused struct mg_connection *conn,
+ __rte_unused void *cbdata)
+{
+ cmdline_quit(pipe_cl);
+ return 0;
+}
+
+int dbg_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+
+ if (!strcmp(ri->request_method, "GET")) {
+ mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n");
+ mg_printf(conn, "Connection: close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<h2> These are the methods supported</h2>");
+ mg_printf(conn, "<h3> /pipelines\n</h3>");
+ mg_printf(conn, "<h3> /cmd \n</h3>");
+ mg_printf(conn, "<h3> /run\n</h3>");
+ mg_printf(conn, "</body></html>");
+ }
+
+ return 1;
+
+}
+
+int get_pipelines_tokens(char *buf)
+{
+ char *token;
+ uint32_t id;
+
+ token = strtok(buf, "/ ");
+ if (strcmp(token, "pipelines")) {
+ return -1;
+ }
+
+ token = strtok(NULL, "/ ");
+ id = atoi(token);
+ if (id > rapp->n_pipelines) {
+ return -1;
+ }
+
+ return id;
+}
+
+
+int dbg_pipelines_id_handler(struct mg_connection *conn,
+ __rte_unused void *cbdata)
+{
+ struct app_eal_params *p = &rapp->eal_params;
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+ //uint32_t id = (uint32_t *)cbdata;
+
+ mg_printf(conn, "Inside dbg_pipelines_id_handler\n");
+
+ if (!strcmp(ri->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ if (p->log_level_present) {
+ mg_printf(conn, "<h2> The pipeline log level is %d</h2>",
+ p->log_level);
+ } else {
+ mg_printf(conn, "<h2> No log level found in the\
+ pipeline</h2>");
+ }
+ mg_printf(conn, "</body></html>");
+ }
+
+ return 1;
+
+}
+
+
+int dbg_pipelines_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+
+ uint32_t i;
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+
+ if (!strcmp(ri->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<h2> These are pipelines available</h2>");
+ for (i = 0; i < rapp->n_pipelines; i++) {
+ mg_printf(conn, "<h3> pipeline %d: %s\n</h3>",i,
+ rapp->pipeline_params[i].type);
+ }
+ mg_printf(conn, "</body></html>");
+ }
+
+ return 1;
+
+}
+
+int dbg_cmd_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ struct app_params *app = rapp;
+ uint8_t msg[2];
+ int status;
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ char buf[MAX_BUF_SIZE];
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<h2> The last command executed </h2>");
+ mg_printf(conn, "<h3> cmd: %d\n </h3>", current_dbg.cmd);
+ mg_printf(conn, "<h3> d1 : %d\n </h3>", current_dbg.d1);
+ mg_printf(conn, "<h3> pipeline : %d\n </h3>",
+ current_dbg.pipe_num);
+ mg_printf(conn, "</body></html>\n");
+
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection:");
+ mg_printf(conn, " close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn, "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "</body></html>\n");
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "cmd")) {
+ current_dbg.cmd = atoi(json_object_get_string(val));
+ } else if (!strcmp(key, "d1")) {
+ current_dbg.d1 = atoi(json_object_get_string(val));
+ } else if (!strcmp(key, "pipeline")) {
+ current_dbg.pipe_num = atoi(json_object_get_string(val));
+ }
+ }
+
+
+ msg[0] = current_dbg.cmd;
+ msg[1] = current_dbg.d1;
+ status = app_pipeline_arpicmp_entry_dbg(app, current_dbg.pipe_num, msg);
+
+ if (status != 0) {
+ mg_printf(conn, "Dbg Command failed\n");
+ return 1;
+ }
+
+ return 1;
+}
+
+int set_sym_hash_per_port(struct mg_connection *conn, uint32_t port_id)
+{
+ int ret;
+ struct rte_eth_hash_filter_info info;
+
+ if (rte_eth_dev_filter_supported(port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ mg_printf(conn, "RTE_ETH_FILTER_HASH not supported on port: %d\n",
+ port_id);
+ return 1;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+ if (ret < 0) {
+ mg_printf(conn, "Cannot set symmetric hash enable per port on "
+ "port %u\n", port_id);
+ return 1;
+ }
+
+ return 1;
+}
+
+int set_hash_input_set_4(struct mg_connection *conn, uint32_t port_id,
+ char *flow_type, char *inset_field0, char *inset_field1,
+ char *inset_field2, char *inset_field3, const char *select)
+{
+ struct rte_eth_hash_filter_info info;
+
+ if (enable_flow_dir) {
+ mg_printf(conn, "FDIR Filter is Defined!\n");
+ mg_printf(conn, "Please undefine FDIR_FILTER flag and define "
+ "HWLD flag\n");
+ return 1;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+ info.info.input_set_conf.flow_type = str2flowtype(flow_type);
+
+ info.info.input_set_conf.field[0] = str2inset(inset_field0);
+ info.info.input_set_conf.field[1] = str2inset(inset_field1);
+ info.info.input_set_conf.field[2] = str2inset(inset_field2);
+ info.info.input_set_conf.field[3] = str2inset(inset_field3);
+
+ info.info.input_set_conf.inset_size = 4;
+ if (!strcmp(select, "select"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+ else if (!strcmp(select, "add"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+ rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+
+ mg_printf(conn, "Command Passed!\n");
+ return 1;
+}
+
+int set_hash_input_set_2(struct mg_connection *conn, uint32_t port_id,
+ const char *flow_type, const char *inset_field0,
+ const char *inset_field1, const char *select)
+{
+ struct rte_eth_hash_filter_info info;
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "</body></html>\n");
+
+ if (enable_flow_dir) {
+ mg_printf(conn, "FDIR Filter is Defined!\n");
+ mg_printf(conn, "Please undefine FDIR_FILTER flag and define "
+ "HWLD flag\n");
+ return 1;
+ }
+
+ if (enable_flow_dir) {
+ mg_printf(conn, "FDIR Filter is Defined!\n");
+ mg_printf(conn, "Please undefine FDIR_FILTER flag and define "
+ "HWLD flag\n");
+ return 1;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+ info.info.input_set_conf.flow_type = str2flowtype(strdup(flow_type));
+
+ info.info.input_set_conf.field[0] = str2inset(strdup(inset_field0));
+ info.info.input_set_conf.field[1] = str2inset(strdup(inset_field1));
+
+ info.info.input_set_conf.inset_size = 2;
+
+ if (!strcmp(select, "select"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+ else if (!strcmp(select, "add"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+ rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+
+ mg_printf(conn, "Command Passed!\n");
+ return 1;
+}
+
+void print_interface_details_rest(struct mg_connection *conn, uint32_t link)
+{
+ l2_phy_interface_t *port;
+ int i = 0;
+ struct sockaddr_in ip;
+ mg_printf(conn, "\n\r");
+
+ if (USE_RTM_LOCKS)
+ rtm_lock();
+ else
+ rte_rwlock_read_lock(&rwlock);
+
+ i = link;
+ port = ifm.port_list[i];
+ mg_printf(conn, "%u", port->pmdid);
+ if (port->ifname && strlen(port->ifname)) {
+ mg_printf(conn, " (%s)\t", port->ifname);
+ } else
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "MAC:%02x:%02x:%02x:%02x:%02x:%02x Adminstate:%s"
+ " Operstate:%s \n\r<br/>",
+ port->macaddr[0], port->macaddr[1],
+ port->macaddr[2], port->macaddr[3],
+ port->macaddr[4], port->macaddr[5],
+ port->admin_status ? "UP" : "DOWN",
+ port->link_status ? "UP" : "DOWN");
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "Speed: %u, %s-duplex\n\r<br/>", port->link_speed,
+ port->link_duplex ? "full" : "half");
+ mg_printf(conn, "\t\t");
+
+ if (port->ipv4_list != NULL) {
+ ip.sin_addr.s_addr =
+ (unsigned long)((ipv4list_t *) (port->ipv4_list))->
+ ipaddr;
+ mg_printf(conn, "IP: %s/%d", inet_ntoa(ip.sin_addr),
+ ((ipv4list_t *) (port->ipv4_list))->addrlen);
+ } else {
+ mg_printf(conn, "IP: NA");
+ }
+
+ mg_printf(conn, "\r\n<br/>");
+ mg_printf(conn, "\t\t");
+ if (port->ipv6_list != NULL) {
+ uint8_t *addr =
+ ((ipv6list_t *) (port->ipv6_list))->ipaddr;
+ mg_printf(conn, "IPv6: %02x%02x:%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4],
+ addr[5], addr[6], addr[7], addr[8], addr[9],
+ addr[10], addr[11], addr[12], addr[13], addr[14],
+ addr[15]);
+ } else {
+ mg_printf(conn, "IPv6: NA");
+ }
+
+ if (port->flags & IFM_SLAVE) {
+ mg_printf(conn, " IFM_SLAVE ");
+ mg_printf(conn, " MasterPort: %u",
+ port->bond_config->bond_portid);
+ }
+ if (port->flags & IFM_MASTER) {
+ mg_printf(conn, " IFM_MASTER ");
+ mg_printf(conn, " Mode: %u", port->bond_config->mode);
+ mg_printf(conn, " PrimaryPort: %u",
+ port->bond_config->primary);
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\t\tSlavePortCount: %u",
+ port->bond_config->slave_count);
+ mg_printf(conn, " SlavePorts:");
+ int i;
+ for (i = 0; i < port->bond_config->slave_count; i++) {
+ mg_printf(conn, " %u ",
+ port->bond_config->slaves[i]);
+ }
+ mg_printf(conn, " ActivePortCount: %u",
+ port->bond_config->active_slave_count);
+ mg_printf(conn, " ActivePorts:");
+ for (i = 0; i < port->bond_config->active_slave_count;
+ i++) {
+ mg_printf(conn, " %u ",
+ port->bond_config->active_slaves[i]);
+ }
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "Link_monitor_freq: %u ms ",
+ port->bond_config->internal_ms);
+ mg_printf(conn, " Link_up_prop_delay: %u ms ",
+ port->bond_config->link_up_delay_ms);
+ mg_printf(conn, " Link_down_prop_delay: %u ms ",
+ port->bond_config->link_down_delay_ms);
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "Xmit_policy: %u",
+ port->bond_config->xmit_policy);
+ }
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "n_rxpkts: %" PRIu64 " ,n_txpkts: %" PRIu64 " ,",
+ port->n_rxpkts, port->n_txpkts);
+ struct rte_eth_stats eth_stats;
+ rte_eth_stats_get(port->pmdid, &eth_stats);
+ mg_printf(conn, "pkts_in: %" PRIu64 " ,", eth_stats.ipackets);
+ mg_printf(conn, "pkts_out: %" PRIu64 " ", eth_stats.opackets);
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\t\t");
+ mg_printf(conn, "in_errs: %" PRIu64 " ,", eth_stats.ierrors);
+ mg_printf(conn, "in_missed: %" PRIu64 " ,", eth_stats.imissed);
+ mg_printf(conn, "out_errs: %" PRIu64 " ,", eth_stats.oerrors);
+ mg_printf(conn, "mbuf_errs: %" PRIu64 " ", eth_stats.rx_nombuf);
+ mg_printf(conn, "\n\r<br/>");
+ mg_printf(conn, "\n\r");
+
+ if (USE_RTM_LOCKS)
+ rtm_unlock();
+ else
+ rte_rwlock_read_unlock(&rwlock);
+}
+
+void print_link_info(struct app_link_params *p, struct mg_connection *conn)
+{
+ struct rte_eth_stats stats;
+ struct ether_addr *mac_addr;
+ uint32_t netmask = (~0U) << (32 - p->depth);
+ uint32_t host = p->ip & netmask;
+ uint32_t bcast = host | (~netmask);
+
+ memset(&stats, 0, sizeof(stats));
+ rte_eth_stats_get(p->pmd_id, &stats);
+
+ mac_addr = (struct ether_addr *) &p->mac_addr;
+
+ if (strlen(p->pci_bdf))
+ mg_printf(conn, "%s(%s): flags=%s\r\n<br/>",
+ p->name,
+ p->pci_bdf,
+ (p->state) ? "UP" : "DOWN");
+ else
+ mg_printf(conn, "%s: flags=%s\r\n<br/>",
+ p->name,
+ (p->state) ? "UP" : "DOWN");
+ if (p->ip)
+ mg_printf(conn, "\tinet %" PRIu32 ".%" PRIu32
+ ".%" PRIu32 ".%" PRIu32
+ " netmask %" PRIu32 ".%" PRIu32
+ ".%" PRIu32 ".%" PRIu32 " "
+ "broadcast %" PRIu32 ".%" PRIu32
+ ".%" PRIu32 ".%" PRIu32 "\r\n<br/>",
+ (p->ip >> 24) & 0xFF,
+ (p->ip >> 16) & 0xFF,
+ (p->ip >> 8) & 0xFF,
+ p->ip & 0xFF,
+ (netmask >> 24) & 0xFF,
+ (netmask >> 16) & 0xFF,
+ (netmask >> 8) & 0xFF,
+ netmask & 0xFF,
+ (bcast >> 24) & 0xFF,
+ (bcast >> 16) & 0xFF,
+ (bcast >> 8) & 0xFF,
+ bcast & 0xFF);
+ mg_printf(conn, "\tether %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
+ ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\r\n<br/>",
+ mac_addr->addr_bytes[0],
+ mac_addr->addr_bytes[1],
+ mac_addr->addr_bytes[2],
+ mac_addr->addr_bytes[3],
+ mac_addr->addr_bytes[4],
+ mac_addr->addr_bytes[5]);
+
+ mg_printf(conn, "\tRX packets %" PRIu64
+ " bytes %" PRIu64
+ "\r\n<br/>",
+ stats.ipackets,
+ stats.ibytes);
+
+ mg_printf(conn, "\tRX errors %" PRIu64
+ " missed %" PRIu64
+ " no-mbuf %" PRIu64
+ "\r\n<br/>",
+ stats.ierrors,
+ stats.imissed,
+ stats.rx_nombuf);
+
+ mg_printf(conn, "\tTX packets %" PRIu64
+ " bytes %" PRIu64 "\r\n<br/>",
+ stats.opackets,
+ stats.obytes);
+
+ mg_printf(conn, "\tTX errors %" PRIu64
+ "\r\n<br/>",
+ stats.oerrors);
+
+ mg_printf(conn, "\r\n<br/>");
+}
+
+int get_link_tokens(char *buf)
+{
+ char *token;
+ int linkid;
+
+ token = strtok(buf, "/ ");
+ if (strcmp(token, "link")) {
+ return -1;
+ }
+
+ token = strtok(NULL, "/ ");
+ linkid = atoi(token);
+ if (linkid > current_cfg.num_ports) {
+ return -1;
+ }
+
+ return linkid;
+}
+
+int linkls_handler(struct mg_connection *conn, void *cbdata)
+{
+ struct app_params *app = rapp;
+
+ struct app_link_params *p;
+
+ APP_PARAM_FIND_BY_ID(app->link_params, "LINK", *(uint32_t *)cbdata, p);
+ if (p) {
+ print_link_info(p, conn);
+ }
+
+ print_interface_details_rest(conn, *(uint32_t *)cbdata);
+ return 1;
+}
+
+static const char* arp_status[] = {"INCOMPLETE", "COMPLETE", "PROBE", "STALE"};
+
+/* ND IPv6 */
+int nd_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ const void *next_key;
+ void *next_data;
+ uint32_t iter = 0;
+ uint8_t ii = 0;
+ mg_printf(conn, "----------------------------------------------------");
+ mg_printf(conn, "-------------------------------------------------\n<br/>");
+ mg_printf(conn, "\tport hw addr status ip addr\n<br/>");
+
+ mg_printf(conn, "-----------------------------------------------------");
+ mg_printf(conn, "-------------------------------------------------\n<br/>");
+ while (rte_hash_iterate(nd_hash_handle, &next_key, &next_data, &iter) >=
+ 0) {
+
+ struct nd_entry_data *tmp_nd_data =
+ (struct nd_entry_data *)next_data;
+ struct nd_key_ipv6 tmp_nd_key;
+ memcpy(&tmp_nd_key, next_key, sizeof(struct nd_key_ipv6));
+ mg_printf(conn, "\t%4d %02X:%02X:%02X:%02X:%02X:%02X %10s",
+ tmp_nd_data->port,
+ tmp_nd_data->eth_addr.addr_bytes[0],
+ tmp_nd_data->eth_addr.addr_bytes[1],
+ tmp_nd_data->eth_addr.addr_bytes[2],
+ tmp_nd_data->eth_addr.addr_bytes[3],
+ tmp_nd_data->eth_addr.addr_bytes[4],
+ tmp_nd_data->eth_addr.addr_bytes[5],
+ arp_status[tmp_nd_data->status]);
+ mg_printf(conn, "\t");
+ for (ii = 0; ii < ND_IPV6_ADDR_SIZE; ii += 2) {
+ mg_printf(conn, "%02X%02X ", tmp_nd_data->ipv6[ii],
+ tmp_nd_data->ipv6[ii + 1]);
+ }
+ mg_printf(conn, "\n<br/>");
+ }
+
+ mg_printf(conn, "\nND IPV6 Stats: \nTotal Queries %u, ok_NH %u,"
+ " no_NH %u, ok_Entry %u, "
+ "no_Entry %u, PopulateCall %u, Del %u, Dup %u\n<br/>",
+ lib_nd_get_mac_req, lib_nd_nh_found, lib_nd_no_nh_found,
+ lib_nd_nd_entry_found, lib_nd_no_arp_entry_found,
+ lib_nd_populate_called, lib_nd_delete_called,
+ lib_nd_duplicate_found);
+ mg_printf(conn, "ND table key len is %lu\n\n<br/>", sizeof(struct nd_key_ipv6));
+ return 0;
+}
+
+int arpls_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ const void *next_key;
+ void *next_data;
+ uint32_t iter = 0, len = 0;
+ char buf[1024];
+
+ len += sprintf
+ (buf + len, "---------------------- ARP CACHE ---------------------\n<br/>");
+ len += sprintf
+ (buf + len, "------------------------------------------------------\n<br/>");
+ len += sprintf(buf + len, "\tport hw addr status ip addr\n<br/>");
+ len += sprintf
+ (buf + len, "------------------------------------------------------\n<br/>");
+
+ while (rte_hash_iterate(arp_hash_handle, &next_key, &next_data, &iter)
+ >= 0) {
+
+ struct arp_entry_data *tmp_arp_data =
+ (struct arp_entry_data *)next_data;
+ struct arp_key_ipv4 tmp_arp_key;
+ memcpy(&tmp_arp_key, next_key, sizeof(struct arp_key_ipv4));
+ len += sprintf
+ (buf + len, "\t%4d %02X:%02X:%02X:%02X:%02X:%02X"
+ " %10s %d.%d.%d.%d\n<br/>",
+ tmp_arp_data->port, tmp_arp_data->eth_addr.addr_bytes[0],
+ tmp_arp_data->eth_addr.addr_bytes[1],
+ tmp_arp_data->eth_addr.addr_bytes[2],
+ tmp_arp_data->eth_addr.addr_bytes[3],
+ tmp_arp_data->eth_addr.addr_bytes[4],
+ tmp_arp_data->eth_addr.addr_bytes[5],
+ arp_status[tmp_arp_data->status],
+ (tmp_arp_data->ip >> 24),
+ ((tmp_arp_data->ip & 0x00ff0000) >> 16),
+ ((tmp_arp_data->ip & 0x0000ff00) >> 8),
+ ((tmp_arp_data->ip & 0x000000ff)));
+ }
+
+ uint32_t i = 0, j;
+ len += sprintf(buf + len, "\n<br/>IP_Address Mask Port\n<br/>");
+ for (j = 0; j < gw_get_num_ports(); j++) {
+ for (i = 0; i < p_route_data[j]->route_ent_cnt; i++) {
+ len += sprintf(buf + len, "0x%08x \t 0x%08x \t %d\n<br/>",
+ p_route_data[j]->route_table[i].nh,
+ p_route_data[j]->route_table[i].mask,
+ p_route_data[j]->route_table[i].port);
+ }
+ }
+
+ len += sprintf
+ (buf + len, "\nARP Stats: Total Queries %u, ok_NH %u,"
+ " no_NH %u, ok_Entry %u, no_Entry %u, PopulateCall %u,"
+ " Del %u, Dup %u\n<br/>",
+ lib_arp_get_mac_req, lib_arp_nh_found, lib_arp_no_nh_found,
+ lib_arp_arp_entry_found, lib_arp_no_arp_entry_found,
+ lib_arp_populate_called, lib_arp_delete_called,
+ lib_arp_duplicate_found);
+
+ len += sprintf(buf + len, "ARP table key len is %lu\n<br/>",
+ sizeof(struct arp_key_ipv4));
+ mg_printf(conn, "%s\n<br/>", &buf[0]);
+ return 1;
+}
+
+void get_mac(struct ether_addr *mac_addr, char *buf)
+{
+ uint32_t i = 0, j = 0, k = 0, MAC_NUM_BYTES = 6;
+
+ char byteStr[MAC_NUM_BYTES][3];
+
+ char *token = strtok(buf, " ");
+ while (token) {
+ k = 0;
+ for (i = 0; i < MAC_NUM_BYTES; i++) {
+ for (j = 0; j < 2; j++) {
+ byteStr[i][j] = token[k++];
+ }
+ byteStr[i][j] = '\0';
+ k++;
+ }
+ token = strtok(NULL, " ");
+ }
+
+ for (i = 0; i < MAC_NUM_BYTES; i++) {
+ mac_addr->addr_bytes[i] = strtoul(byteStr[i], NULL, 16);
+ }
+}
+
+int arp_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ char buf[MAX_BUF_SIZE];
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ /* prints arp table */
+ mg_printf(conn, "<html><body>");
+ arpls_handler(conn, cbdata);
+
+ /* prints nd table */
+ nd_handler(conn, cbdata);
+ mg_printf(conn, "</body></html>");
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "ipv4")) {
+ current_arp_parms.ip = rte_bswap32(inet_addr(
+ json_object_get_string(val)));
+ current_arp_parms.family = AF_INET;
+ } else if (!strcmp(key, "ipv6")) {
+ my_inet_pton_ipv6(AF_INET6,
+ json_object_get_string(val),
+ &current_arp_parms.ipv6[0]);
+ current_arp_parms.family = AF_INET6;
+ } else if (!strcmp(key, "action")) {
+ if (!strcmp(json_object_get_string(val), "add"))
+ current_arp_parms.action = 1;
+ else if (!strcmp(json_object_get_string(val), "del"))
+ current_arp_parms.action = 2;
+ else if (!strcmp(json_object_get_string(val), "req"))
+ current_arp_parms.action = 3;
+ } else if (!strcmp(key, "portid")) {
+ current_arp_parms.portid =
+ atoi(json_object_get_string(val));
+ } else if (!strcmp(key, "macaddr")) {
+ get_mac(&current_arp_parms.mac_addr,
+ strdup(json_object_get_string(val)));
+ }
+ }
+
+ struct arp_key_ipv4 arp_key;
+ struct arp_timer_key *callback_key;
+ struct arp_entry_data *new_arp_data;
+ struct nd_key_ipv6 nd_key;
+ struct nd_entry_data *new_nd_data;
+
+ if (current_arp_parms.family == AF_INET) {
+ switch(current_arp_parms.action) {
+ case 1:
+ populate_arp_entry(&current_arp_parms.mac_addr,
+ current_arp_parms.ip, current_arp_parms.portid,
+ STATIC_ARP);
+ break;
+ case 2:
+ callback_key =
+ (struct arp_timer_key*) rte_malloc(NULL,
+ sizeof(struct arp_timer_key*),
+ RTE_CACHE_LINE_SIZE);
+ arp_key.port_id = current_arp_parms.portid;
+ arp_key.ip = current_arp_parms.ip;
+ arp_key.filler1 = 0;
+ arp_key.filler2 = 0;
+ arp_key.filler3 = 0;
+ new_arp_data = retrieve_arp_entry(arp_key,
+ STATIC_ARP);
+ callback_key->port_id = current_arp_parms.portid;
+ callback_key->ip = current_arp_parms.ip;
+
+ mg_printf(conn, "removing entry now\n");
+ remove_arp_entry(new_arp_data, callback_key);
+ break;
+ case 3:
+ arp_key.ip = current_arp_parms.ip;
+ arp_key.port_id = current_arp_parms.portid;
+ arp_key.filler1 = 0;
+ arp_key.filler2 = 0;
+ arp_key.filler3 = 0;
+
+ new_arp_data = retrieve_arp_entry(arp_key, STATIC_ARP);
+
+ if (new_arp_data) {
+ mg_printf(conn, "<p>ARP entry exists for"
+ " ip 0x%x, port %d</p>",
+ current_arp_parms.ip, current_arp_parms.portid);
+ return 1;
+ }
+
+ mg_printf(conn, "<p>ARP - requesting arp for ip 0x%x, port %d</p>",
+ current_arp_parms.ip, current_arp_parms.portid);
+
+ request_arp(current_arp_parms.portid, current_arp_parms.ip);
+ break;
+ default:
+ break;
+ };
+ } else {
+ switch(current_arp_parms.action) {
+ case 1:
+ populate_nd_entry(&current_arp_parms.mac_addr,
+ current_arp_parms.ipv6, current_arp_parms.portid, STATIC_ND);
+ break;
+ case 2:
+ nd_key.port_id = current_arp_parms.portid;
+ memcpy(&nd_key.ipv6[0], &current_arp_parms.ipv6[0], 16);
+ nd_key.filler1 = 0;
+ nd_key.filler2 = 0;
+ nd_key.filler3 = 0;
+ new_nd_data = retrieve_nd_entry(nd_key, STATIC_ND);
+ remove_nd_entry_ipv6(new_nd_data, &nd_key);
+ case 3:
+ mg_printf(conn, "<p>ND REQ is not supported Yet!!!</p>");
+ break;
+ default:
+ break;
+ };
+ }
+
+ mg_printf(conn, "<p>Command Passed</p>");
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+}
+
+int route_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ uint32_t portid = 0;
+ uint32_t i, j, status;
+ char buf[MAX_BUF_SIZE];
+ uint32_t mask = 0, num = 31;
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<pre>\nIP_Address Mask Port\n<br/>");
+
+ for (j = 0; j < gw_get_num_ports(); j++) {
+ for (i = 0; i < p_route_data[j]->route_ent_cnt; i++) {
+ mg_printf(conn, "0x%08x \t 0x%08x \t %d\n<br/>",
+ p_route_data[j]->route_table[i].nh,
+ p_route_data[j]->route_table[i].mask,
+ p_route_data[j]->route_table[i].port);
+ }
+ }
+
+ mg_printf(conn, "\n\nND IPV6 routing table ...\n<br/>");
+ mg_printf(conn, "\nNH_IP_Address "
+ " Depth Port \n<br/>");
+ for(uint32_t p = 0; p < gw_get_num_ports(); p++ ) {
+ for (i = 0; i < p_nd_route_data[p]->nd_route_ent_cnt; i++) {
+ for (j = 0; j < ND_IPV6_ADDR_SIZE; j += 2) {
+ mg_printf(conn, "%02X%02X ",
+ p_nd_route_data[p]->nd_route_table[i].nhipv6[j],
+ p_nd_route_data[p]->nd_route_table[i].nhipv6[j + 1]);
+ }
+
+ mg_printf(conn, "\t%d %d "
+ " \n<br/></pre>",
+ p_nd_route_data[p]->nd_route_table[i].depth,
+ p_nd_route_data[p]->nd_route_table[i].port);
+ }
+ }
+
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "portid")) {
+ portid = atoi(json_object_get_string(val));
+ if (portid > 64) {
+ mg_printf(conn, "Port not supported!!!\n");
+ return 1;
+ } else if (current_route_parms[portid].enable) {
+ mg_printf(conn, "Already configured\n");
+ }
+ } else if (!strcmp(key, "nhipv4")) {
+ current_route_parms[portid].ip =
+ rte_bswap32(inet_addr(json_object_get_string(val)));
+ current_route_parms[portid].family = AF_INET;
+ } else if (!strcmp(key, "nhipv6")) {
+ my_inet_pton_ipv6(AF_INET6,
+ json_object_get_string(val), &current_route_parms[portid].ipv6[0]);
+ current_route_parms[portid].family = AF_INET6;
+ } else if (!strcmp(key, "depth")) {
+ current_route_parms[portid].depth = atoi(json_object_get_string(val));
+ current_route_parms[portid].enable = 1;
+ } else if (!strcmp(key, "type")) {
+ memcpy(current_route_parms[portid].type, json_object_get_string(val),
+ strlen(json_object_get_string(val)));
+ }
+ }
+
+ if (current_route_parms[portid].family == AF_INET) {
+ if (!strcmp(current_route_parms[portid].type, "net")) {
+ for (i = 0; i < current_route_parms[portid].depth; i++) {
+ mask |= (1 << num);
+ num--;
+ }
+ } else
+ mask = 0xFFFFFFFF;
+
+ status = app_routeadd_config_ipv4(rapp, portid,
+ current_route_parms[portid].ip,
+ mask);
+ if (status != 0)
+ mg_printf(conn, "Setting route entry failed\n");
+ } else {
+
+ if (!strcmp(current_route_parms[portid].type, "host")) {
+ current_route_parms[portid].depth = 128;
+ }
+ status = app_routeadd_config_ipv6(rapp, portid,
+ current_route_parms[portid].ipv6,
+ current_route_parms[portid].depth);
+ if (status != 0)
+ mg_printf(conn, "Setting route entry failed\n");
+ }
+
+
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+}
+
+int link_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ int i, status = 0, link = 0, link_read = 0;
+ char buf[MAX_BUF_SIZE];
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>\n");
+ for (i = 0; i < MAX_LINKS; i++) {
+ if (current_link_parms[i].state)
+ mg_printf(conn, "link %d is enabled\r\n", i);
+ }
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "linkid")) {
+ link = atoi(json_object_get_string(val));
+ mg_printf(conn, "linkid:%d \n", link);
+ if (link > 64) {
+ mg_printf(conn, "Link id not supported beyond 64\n");
+ return 1;
+ }
+ current_link_parms[link].id = link;
+ link_read = 1;
+ } else if (!strcmp(key, "state")) {
+ if (link_read) {
+ current_link_parms[link].state =
+ atoi(json_object_get_string(val));
+ }
+ mg_printf(conn, "state:%d \n", current_link_parms[link].state);
+ }
+
+ }
+
+
+ if (current_link_parms[link].state == 0) {
+ /* link down */
+ status = app_link_down(rapp, current_link_parms[link].id);
+ if (status != 0) {
+ mg_printf(conn, "<p>command failed</p>");
+ } else {
+ mg_printf(conn, "<p>command Passed</p>");
+ }
+ } else if (current_link_parms[link].state == 1) {
+ /* link up */
+ mg_printf(conn, "setting up the link \n");
+ status = app_link_up(rapp, current_link_parms[link].id);
+ if (status != 0) {
+ mg_printf(conn, "<p>command failed</p>");
+ } else {
+ mg_printf(conn, "<p>command Passed</p>");
+ }
+
+ }
+
+ sprintf(buf, "/vnf/config/link/%d", link);
+ mg_set_request_handler(ctx, buf, linkid_handler, (void *)&link);
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ return 1;
+}
+
+int linkid_handler(struct mg_connection *conn, void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ int status = 0;
+ char buf[MAX_BUF_SIZE];
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>\n");
+ linkls_handler(conn, cbdata);
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+
+ uint32_t linkid = *(uint32_t *)cbdata;
+ mg_printf(conn, "link id :%d ", linkid);
+
+ if (!current_link_parms[linkid].state) {
+ mg_printf(conn, "<p>link not enabled!! </p>");
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+ }
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "ipv4")) {
+ current_link_parms[linkid].ip =
+ rte_bswap32(inet_addr(json_object_get_string(val)));
+ current_link_parms[linkid].family = AF_INET;
+ } else if (!strcmp(key, "ipv6")) {
+ my_inet_pton_ipv6(AF_INET6,
+ json_object_get_string(val), &current_link_parms[linkid].ipv6[0]);
+ current_link_parms[linkid].family = AF_INET6;
+ } else if (!strcmp(key, "depth")) {
+ current_link_parms[linkid].depth = atoi(json_object_get_string(val));
+ }
+ }
+
+
+ /* bring the link down */
+ status = app_link_down(rapp, linkid);
+ if (status != 0) {
+ mg_printf(conn, "<p>command down failed</p>");
+ } else {
+ mg_printf(conn, "<p>command Passed</p>");
+ }
+
+ /* configure the ip address */
+ if (current_link_parms[linkid].family == AF_INET) {
+ status = app_link_config(rapp, linkid, current_link_parms[linkid].ip,
+ current_link_parms[linkid].depth);
+ } else {
+ status = app_link_config_ipv6(rapp, linkid,
+ current_link_parms[linkid].ipv6, current_link_parms[linkid].depth);
+ }
+
+ if (status != 0) {
+ mg_printf(conn, "<p>command config failed</p>");
+ } else {
+ mg_printf(conn, "<p>command Passed</p>");
+ }
+
+ /* bring the link up */
+ status = app_link_up(rapp, linkid);
+ if (status != 0) {
+ mg_printf(conn, "<p>command up failed</p>");
+ } else {
+ mg_printf(conn, "<p>command Passed</p>");
+ }
+
+
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+}
+
+void set_vnf_type(const char *type)
+{
+ memcpy(current_cfg.vnf_type, type, strlen(type));
+}
+
+void init_stat_cfg(void)
+{
+ char buf[256] = "98103214:(1, 65535)";
+ uint32_t i;
+
+ current_cfg.num_workers = 4;
+ current_cfg.num_lb = 1;
+ current_cfg.num_ports = 2;
+ current_cfg.hyper_thread = 0;
+ current_cfg.sock_in = 0;
+ current_cfg.sw_lb = 1;
+ memcpy(current_cfg.pkt_type, "ipv4", 4);
+
+ for (i=0;i<MAX_LB;i++) {
+ memcpy(current_cfg.ip_range[i].value, &buf,
+ sizeof(buf));
+ }
+}
+
+void bind_the_ports(struct mg_connection *conn, char *pci_white_list)
+{
+ char *token;
+ char buf[MAX_BUF_SIZE];
+ int x = 0, ret;
+
+ token = strtok(pci_white_list, " ");
+
+ while(token != NULL) {
+ mg_printf(conn, "%s ****\n", token);
+ sprintf(buf, "$RTE_SDK/usertools/dpdk-devbind.py -u %s", token);
+ ret = system(buf);
+ if (ret)
+ mg_printf(conn, "wrong parameter sent\n");
+
+ sprintf(buf, "$RTE_SDK/usertools/dpdk-devbind.py -b igb_uio %s", token);
+ ret = system(buf);
+ if (ret)
+ mg_printf(conn, "wrong parameter sent\n");
+
+ token = strtok(NULL, " ");
+
+ x++;
+ }
+ current_cfg.num_ports = x;
+}
+
+int static_cfg_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ int i;
+ unsigned int len;
+ char buf[MAX_BUF_SIZE];
+
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+
+ if (!strcmp(ri->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<h2> These are the values set in config</h2>");
+ mg_printf(conn, "<h3> num_workers: %d\n</h3>",
+ current_cfg.num_workers);
+ mg_printf(conn, "<h3> num_lb: %d\n</h3>",
+ current_cfg.num_lb);
+ mg_printf(conn, "<h3> num_ports: %d\n</h3>",
+ current_cfg.num_ports);
+ mg_printf(conn, "<h3> hyper_thread: %d\n</h3>",
+ current_cfg.hyper_thread);
+ mg_printf(conn, "<h3> socket_id : %d\n</h3>",
+ current_cfg.sock_in);
+ mg_printf(conn, "<h3> sw_lb: %d\n</h3>",
+ current_cfg.sw_lb);
+ mg_printf(conn, "<h3> vnf_type: %s\n</h3>",
+ current_cfg.vnf_type);
+ mg_printf(conn, "<h3> pkt_type: %s\n</h3>",
+ current_cfg.pkt_type);
+ mg_printf(conn, "<h3> pci_white_list: %s\n</h3>",
+ current_cfg.pci_white_list);
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+ }
+
+ if (strcmp(ri->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ ri->request_method);
+ return 1;
+ }
+
+ if (static_cfg_set) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ return 1;
+ }
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ len = 0;
+ struct json_object *values;
+ char *str;
+
+ i = 0;
+ json_object_object_foreach(jobj, key, val) {
+ memcpy(static_cfg[i].key, key, strlen(key));
+ memcpy(static_cfg[i].value, json_object_get_string(val),
+ strlen(json_object_get_string(val)));
+ sprintf(buf, "public_ip_port_range_%d", pub_ip);
+ if (!strcmp(static_cfg[i].key, buf)) {
+ memcpy(&current_cfg.ip_range[pub_ip].value,
+ static_cfg[i].value,
+ sizeof(static_cfg[i].value));
+ pub_ip++;
+ }
+ i++;
+ }
+ n_entries1 = i;
+
+ json_object_object_get_ex(jobj, "num_worker", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ memcpy(&current_cfg.ip_range[pub_ip++].value, str,
+ sizeof(str));
+ }
+
+ json_object_object_get_ex(jobj, "num_worker", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.num_workers = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "pkt_type", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ memcpy(&current_cfg.pkt_type, str,
+ sizeof(current_cfg.pkt_type));
+ }
+
+ json_object_object_get_ex(jobj, "num_lb", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.num_lb = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "num_ports", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.num_ports = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "sw_lb", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.sw_lb = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "sock_in", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.sock_in = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "hyperthread", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ current_cfg.hyper_thread = atoi(str);
+ }
+
+ json_object_object_get_ex(jobj, "vnf_type", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ memcpy(&current_cfg.vnf_type, str,
+ sizeof(current_cfg.vnf_type));
+ }
+
+ json_object_object_get_ex(jobj, "pci_white_list", &values);
+ if (values) {
+ str = strdup(json_object_get_string(values));
+ if (str)
+ memcpy(&current_cfg.pci_white_list, str,
+ sizeof(current_cfg.pci_white_list));
+ mg_printf(conn, " Binding the ports \n");
+ bind_the_ports(conn, &current_cfg.pci_white_list[0]);
+ }
+
+ len = sprintf(buf, "POST DATA RECEIVED\n");
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: %u\r\n"
+ "Content-Type: text/plain\r\n"
+ "Connection: close\r\n\r\n",
+ len);
+
+ mg_write(conn, buf, len);
+ post_not_received = 0;
+ static_cfg_set++;
+ return 1;
+}
+
+int vnf_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<h2>These are the methods that are supported</h2>");
+ mg_printf(conn, "<h3> /vnf/config</h3>");
+ mg_printf(conn, "<h3> /vnf/config/arp</h3>");
+ mg_printf(conn, "<h3> /vnf/config/link</h3>");
+ mg_printf(conn, "<h3> /vnf/config/route</h3>");
+ mg_printf(conn, "<h3> /vnf/config/rules(vFW/vACL only)</h3>");
+ mg_printf(conn, "<h3> /vnf/config/rules/load(vFW/vACL only)</h3>");
+ mg_printf(conn, "<h3> /vnf/config/rules/clear(vFW/vACL only)</h3>");
+ mg_printf(conn, "<h3> /vnf/config/nat(vCGNAPT only)</h3>");
+ mg_printf(conn, "<h3> /vnf/config/nat/load(vFW/vACL only)</h3>");
+ mg_printf(conn, "<h3> /vnf/config/dbg</h3>");
+ mg_printf(conn, "<h3> /vnf/config/dbg/pipelines</h3>");
+ mg_printf(conn, "<h3> /vnf/config/dbg/cmd</h3>");
+ mg_printf(conn, "<h3> /vnf/log</h3>");
+ mg_printf(conn, "<h3> /vnf/flowdirector</h3>");
+ mg_printf(conn, "<h3> /vnf/status</h3>");
+ mg_printf(conn, "<h3> /vnf/stats</h3>");
+ mg_printf(conn, "<h3> /vnf/quit</h3>");
+ mg_printf(conn, "</body></html>");
+
+
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+ mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+ mg_printf(conn,
+ "%s method not allowed in the POST handler\n",
+ req_info->request_method);
+ return 1;
+ }
+
+ return 1;
+}
+
+void get_pktq_in_prv(char *buf)
+{
+ int j;
+ uint32_t len = 0;
+ for (j = 0; j < current_cfg.num_ports; j+=2) {
+ len += sprintf(buf + len, "RXQ%d.0 ", j);
+ }
+}
+
+void fix_pipelines_data_types(FILE *f, const char *sect_name, struct rte_cfgfile *tcfg)
+{
+ int i, j, n_entries, tmp = 0;
+ char str[256], str1[40];
+
+ n_entries = rte_cfgfile_section_num_entries(tcfg, sect_name);
+
+ rte_cfgfile_section_entries(tcfg, sect_name, entries, n_entries);
+
+ for (i = 0; i < n_entries; i++) {
+ for (j = 0; j < n_entries1; j++) {
+ if (strncmp(entries[i].name, static_cfg[i].key,
+ strlen(entries[i].name)) == 0) {
+ memcpy(entries[i].value, static_cfg[i].value,
+ strlen(entries[i].value));
+ tmp++;
+ }
+
+ if (strncmp(entries[i].name, "pkt_type",
+ strlen("pkt_type")) == 0) {
+ memcpy(entries[i].value, current_cfg.pkt_type,
+ strlen(entries[i].value));
+ if (!strcmp(current_cfg.pkt_type, "ipv4"))
+ memcpy(&traffic_type, "4", 1);
+ else
+ memcpy(&traffic_type, "6", 1);
+ }
+
+ if (strncmp(entries[i].name, "traffic_type",
+ sizeof("traffic_type")) == 0) {
+ memcpy(entries[i].value, &traffic_type, 4);
+ }
+ }
+
+ if (strncmp(entries[i].name, "core", strlen(entries[i].name)) == 0) {
+ if ((strncmp(sect_name, "MASTER", strlen(sect_name)) == 0) &&
+ !current_cfg.sock_in) {
+ continue;
+ }
+
+ if ((current_cfg.hyper_thread) && hyper) {
+ sprintf(str, "s%dc%dh", current_cfg.sock_in,
+ sock_cpus[current_cfg.sock_in][sock_index]);
+ memcpy(entries[i].value, &str, 8);
+ sock_index++;
+ hyper = 0;
+ continue;
+ }
+
+ sprintf(str, "s%dc%d", current_cfg.sock_in,
+ sock_cpus[current_cfg.sock_in][sock_index]);
+
+ if (!current_cfg.hyper_thread)
+ sock_index++;
+ else
+ hyper = 1;
+
+ if (current_cfg.sock_in) {
+ if (sock_index == sock1)
+ sock_index = 1;
+ } else {
+ if (sock_index == sock0)
+ sock_index = 1;
+ }
+ memcpy(entries[i].value, &str, 8);
+ }
+ }
+ num_entries = i;
+
+ if (strncmp(sect_name, "ARPICMP", strlen(sect_name)) == 0) {
+ for (j = 0; j < n_entries1; j++) {
+ if ((strncmp(static_cfg[j].key, "arp_route_tbl",
+ strlen(static_cfg[j].key)) == 0) ||
+ (strncmp(static_cfg[j].key, "nd_route_tbl",
+ strlen(static_cfg[j].key)) == 0)) {
+ memcpy(&entries[i].name, &static_cfg[j].key,
+ strlen(static_cfg[j].key));
+ memcpy(&entries[i].value, &static_cfg[j].value,
+ strlen(static_cfg[j].value));
+ i++;
+ }
+ }
+ num_entries = i;
+ /* update pktq_in/pktq_out */
+ for (i=0; i < n_entries; i++) {
+ memset(str, 0, 256);
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ tmp = (current_cfg.sw_lb)? current_cfg.num_lb: current_cfg.num_workers;
+ get_swq(tmp, &str[0]);
+ memcpy(&entries[i].value, &str, strlen(str));
+ continue;
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ //tmp = (current_cfg.sw_lb)? current_cfg.num_lb: current_cfg.num_workers / 2;
+ //tmp = (current_cfg.sw_lb)? current_cfg.num_lb: current_cfg.num_ports;
+ get_txq(0, 1, current_cfg.num_ports, &str[0]);
+ memcpy(&entries[i].value, &str, strlen(str));
+ continue;
+ }
+
+ if (strncmp(entries[i].name, "pktq_in_prv",
+ strlen(entries[i].name)) == 0) {
+ get_pktq_in_prv(&str[0]);
+ memset(&entries[i].value, 0, sizeof(entries[i].value));
+ memcpy(&entries[i].value, &str, strlen(str));
+ continue;
+ }
+
+ if (strncmp(entries[i].name, "prv_to_pub_map",
+ strlen(entries[i].name)) == 0) {
+ get_prv_to_pub_map(&str[0]);
+ memcpy(&entries[i].value, &str, strlen(str));
+ continue;
+ }
+
+ if (strncmp(entries[i].name, "prv_que_handler",
+ strlen(entries[i].name)) == 0) {
+ get_prv_que_handler(&str[0]);
+ memcpy(&entries[i].value, &str, strlen(str));
+ continue;
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "TXRX-BEGIN", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ get_rxq(0, 1, 2, &str[0]);
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ get_swq(2, &str[0]);
+ memcpy(loadb_in, str, sizeof(str));
+ sprintf(str1," SWQ%d", arp_index++);
+ strcat(str, str1);
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "LOADB", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ memcpy(entries[i].value, &loadb_in, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.num_ports > 2)
+ tmp = (current_cfg.num_workers/current_cfg.num_lb * 2);
+ else
+ tmp = current_cfg.num_workers * 2;
+ start_lb = swq_index;
+ end_lb = tmp;
+ start_lbout = start_lb + end_lb;
+ get_swq(tmp, &str[0]);
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ if (strncmp(entries[i].name, "n_vnf_threads",
+ strlen(entries[i].name)) == 0) {
+ sprintf(str1, "%d", current_cfg.num_workers/current_cfg.num_lb);
+ memcpy(entries[i].value, &str1, sizeof(str1));
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "VACL", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb) {
+ get_swq_offset(start_lb, 2, &str[0]);
+ start_lb += 2;
+ } else
+ get_rxq(workers, 1, 2, &str[0]);
+
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb)
+ get_swq(2, &str[0]);
+ else {
+ get_txq(workers+1, 1, 2, &str[0]);
+ sprintf(str1," SWQ%d", arp_index++);
+ strcat(str, str1);
+ }
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ }
+
+ workers++;
+ if (current_cfg.sw_lb) {
+ if (((workers % current_cfg.num_workers/current_cfg.num_lb) == 0) &&
+ (workers != current_cfg.num_workers)) {
+ workers = 0;
+ }
+ } else {
+ if ((workers % current_cfg.num_workers/current_cfg.num_lb) == 0) {
+ tx_start_port += 2;
+ rx_start_port += 2;
+ workers = 0;
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "VCGNAPT", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb) {
+ get_swq_offset(start_lb, 2, &str[0]);
+ start_lb += 2;
+ } else
+ get_rxq(workers, 1, 2, &str[0]);
+
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb)
+ get_swq(2, &str[0]);
+ else {
+ get_txq(workers+1, 1, 2, &str[0]);
+ sprintf(str1," SWQ%d", arp_index++);
+ strcat(str, str1);
+ }
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ }
+
+ if (workers == 0) {
+ char *token;
+ sprintf(str1, "vnf_set");
+ memcpy(entries[i].name, &str1, sizeof(str1));
+ sprintf(str1, "(3,4,5)");
+ memcpy(entries[i].value, &str1, sizeof(str1));
+ num_entries++;
+ i++;
+
+ token = strtok(current_cfg.ip_range[ip_range].value, "/");
+ while(token) {
+ sprintf(str1, "public_ip_port_range");
+ memcpy(entries[i].name, &str1, sizeof(str1));
+ memcpy(entries[i].value, token, strlen(token));
+ i++;
+ num_entries++;
+ token = strtok(NULL, "/");
+ }
+ ip_range++;
+ }
+
+ workers++;
+ if (current_cfg.sw_lb) {
+ if (((workers % (current_cfg.num_workers/current_cfg.num_lb)) == 0) &&
+ (workers != current_cfg.num_workers)) {
+ workers = 0;
+ }
+ } else {
+ //if (((workers % (current_cfg.num_workers/current_cfg.num_lb)) == 0) &&
+ // (workers != current_cfg.num_workers)) {
+ if (workers == (current_cfg.num_workers/current_cfg.num_lb)) {
+ tx_start_port += 2;
+ rx_start_port += 2;
+ workers = 0;
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "VFW", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb) {
+ get_swq_offset(start_lb, 2, &str[0]);
+ start_lb += 2;
+ } else
+ get_rxq(workers, 1, 2, &str[0]);
+
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ if (current_cfg.sw_lb)
+ get_swq(2, &str[0]);
+ else {
+ get_txq(workers+1, 1, 2, &str[0]);
+ sprintf(str1," SWQ%d", arp_index++);
+ strcat(str, str1);
+ }
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ }
+
+ workers++;
+ if (current_cfg.sw_lb) {
+ if (((workers % current_cfg.num_workers/current_cfg.num_lb) == 0)
+ && (workers != current_cfg.num_workers)) {
+ workers = 0;
+ }
+ } else {
+ if (current_cfg.num_ports > 2) {
+ tx_start_port += 2;
+ rx_start_port += 2;
+ workers = 0;
+ }
+ }
+ }
+
+ if (strncmp(sect_name, "TXRX-END", strlen(sect_name)) == 0) {
+ for (i=0; i < n_entries; i++) {
+ if (strncmp(entries[i].name, "pktq_in",
+ strlen(entries[i].name)) == 0) {
+ get_swq_offset(start_lbout, end_lb, &str[0]);
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+
+ if (strncmp(entries[i].name, "pktq_out",
+ strlen(entries[i].name)) == 0) {
+ get_txq(1, end_lb / 2, 2, &str[0]);
+ memcpy(entries[i].value, &str, sizeof(str));
+ }
+ }
+ tx_start_port += 2;
+ rx_start_port += 2;
+ }
+
+ fprintf(f, "[PIPELINE%d]\n", pipenum);
+ for (i=0;i<num_entries;i++) {
+ fprintf(f, "%s = %s\n", entries[i].name, entries[i].value);
+ }
+ fprintf(f, "\n");
+ pipenum++;
+}
+
+void print_to_file(FILE *f, struct rte_cfgfile *tcfg)
+{
+ int i;
+ for (i=0;i<num_pipelines;i++) {
+ fix_pipelines_data_types(f, pipelines[pipe_arr[i]], tcfg);
+ }
+ fclose(f);
+}
+
+int get_vnf_index(void)
+{
+
+ int i;
+
+ for (i = 0; i < PIPE_MAX; i++) {
+ if (strncmp(pipelines[i], current_cfg.vnf_type,
+ strlen(current_cfg.vnf_type)) == 0)
+ return i;
+ }
+ return -1;
+}
+
+void build_pipeline(void)
+{
+ int i = 2, j, k, vnf_index;
+
+ pipe_arr[0] = 0;
+ pipe_arr[1] = 1;
+ vnf_index = get_vnf_index();
+ if (vnf_index == -1)
+ printf("Wrong VNF TYPE\n");
+
+ if (vnf_index == VNF_VCGNAPT)
+ pipe_arr[i++] = 2;
+
+ if (!current_cfg.sw_lb) {
+ for (k = 0; k < current_cfg.num_workers; k++)
+ pipe_arr[i++] = vnf_index;
+ num_pipelines = i;
+ return;
+ }
+
+ for (j = 0; j < current_cfg.num_lb; j++) {
+ /* put TXRX-BEGIN & LOADB pipelines */
+ pipe_arr[i++] = TXRX_BEGIN;
+ pipe_arr[i++] = LOADB;
+
+ /* place the worker threads */
+ int limit = current_cfg.num_workers / current_cfg.num_lb;
+ for (k = 0; k < limit; k++)
+ pipe_arr[i++] = vnf_index;
+
+ /* end the TXRX pipeline */
+ pipe_arr[i++] = TXRX_END;
+ }
+ num_pipelines = i;
+}
+
+int set_hash_global_config(struct mg_connection *conn, uint32_t port_id,
+ char *flow_type, const char *hash_func, const char *enable)
+{
+ struct rte_eth_hash_filter_info info;
+ uint32_t ftype, idx, offset;
+ int ret;
+
+ if (rte_eth_dev_filter_supported(port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ mg_printf(conn, "RTE_ETH_FILTER_HASH not supported on port %d\n",
+ port_id);
+ return 1;
+ }
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+ if (!strcmp(hash_func, "toeplitz"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+ else if (!strcmp(hash_func, "simple_xor"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+ else if (!strcmp(hash_func, "default"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+ ftype = str2flowtype(flow_type);
+ idx = ftype / (CHAR_BIT * sizeof(uint32_t));
+ offset = ftype % (CHAR_BIT * sizeof(uint32_t));
+ info.info.global_conf.valid_bit_mask[idx] |= (1UL << offset);
+ if (!strcmp(enable, "enable"))
+ if(idx < RTE_SYM_HASH_MASK_ARRAY_SIZE)
+ info.info.global_conf.sym_hash_enable_mask[idx] |=
+ (1UL << offset);
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+ if (ret < 0)
+ mg_printf(conn, "Cannot set global hash configurations by port %d\n",
+ port_id);
+ else
+ mg_printf(conn, "Global hash configurations have been set "
+ "succcessfully by port %d\n", port_id);
+ return 1;
+}
+
+int flow_director_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ uint32_t port_id = 0, tuple = 0;
+ char trans_type[24], buf[MAX_BUF_SIZE];
+ char *str, field0[MAX_SIZE], field1[MAX_SIZE], field2[MAX_SIZE],
+ field3[MAX_SIZE], flow_type[MAX_SIZE];
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ if (flow_dir_cfg)
+ mg_printf(conn, "<h3> Flow is configured </h3>");
+ else
+ mg_printf(conn, "<h3> Flow is NOT configured </h3>");
+ mg_printf(conn, "</body></html>");
+ return 1;
+ }
+
+ if (strcmp(req_info->request_method, "POST")) {
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+ "close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "This method is not supported\n");
+ mg_printf(conn, "</body></html>");
+ return 1;
+
+ }
+
+ mg_read(conn, buf, sizeof(buf));
+ json_object * jobj = json_tokener_parse(buf);
+ json_object_object_foreach(jobj, key, val) {
+ if (!strcmp(key, "trans_type")) {
+ memcpy(&trans_type, str, sizeof(trans_type));
+ if (!strcmp(key, "udp")) {
+ memcpy(field2,"udp-src-port", sizeof("udp-src-port"));
+ memcpy(field3,"udp-dst-port", sizeof("udp-dst-port"));
+ if (!strcmp(current_cfg.pkt_type, "ipv4")) {
+ memcpy(flow_type,"ipv4-udp", sizeof("ipv4-udp"));
+ memcpy(field0,"src-ipv4", sizeof("src-ipv4"));
+ memcpy(field1,"dst-ipv4", sizeof("dst-ipv4"));
+ } else if (!strcmp(current_cfg.pkt_type, "ipv6")) {
+ memcpy(flow_type,"ipv6-udp", sizeof("ipv6-udp"));
+ memcpy(field0,"src-ipv6", sizeof("src-ipv6"));
+ memcpy(field1,"dst-ipv6", sizeof("dst-ipv6"));
+ }
+ } else if (!strcmp(key, "tcp")) {
+ memcpy(field2,"tcp-src-port", sizeof("tcp-src-port"));
+ memcpy(field3,"tcp-dst-port", sizeof("tcp-dst-port"));
+ if (!strcmp(current_cfg.pkt_type, "ipv4")) {
+ memcpy(flow_type,"ipv4-tcp", sizeof("ipv4-tcp"));
+ memcpy(field0,"src-ipv4", sizeof("src-ipv4"));
+ memcpy(field1,"dst-ipv4", sizeof("dst-ipv4"));
+ } else if (!strcmp(current_cfg.pkt_type, "ipv6")) {
+ memcpy(flow_type,"ipv6-tcp", sizeof("ipv6-tcp"));
+ memcpy(field0,"src-ipv6", sizeof("src-ipv6"));
+ memcpy(field1,"dst-ipv6", sizeof("dst-ipv6"));
+ }
+ }
+ } else if (!strcmp(key, "tuple")) {
+ tuple = atoi(json_object_get_string(val));
+ if ((tuple != 2) || (tuple != 5))
+ return 1;
+ }
+ }
+
+ if (tuple == 2) {
+ set_pkt_forwarding_mode("rxonly");
+ for (port_id = 0; port_id < current_cfg.num_ports; port_id++) {
+ set_sym_hash_per_port(conn, port_id);
+ set_hash_global_config(conn, port_id, flow_type,
+ "simple_xor", "enable");
+ }
+
+ for (port_id = 0; port_id < current_cfg.num_ports; port_id+=2) {
+ set_hash_input_set_2(conn, port_id, "ipv4-udp", "src-ipv4",
+ "udp-src-port", "add");
+ set_hash_input_set_2(conn, port_id, "ipv4-udp", "dst-ipv4",
+ "udp-dst-port", "add");
+ set_hash_input_set_2(conn, port_id, "ipv4-udp", "src-ipv6",
+ "udp-src-port", "add");
+ set_hash_input_set_2(conn, port_id, "ipv4-udp", "dst-ipv6",
+ "udp-dst-port", "add");
+ }
+ } else if (tuple == 5) {
+ set_pkt_forwarding_mode("rxonly");
+ for (port_id = 0; port_id < current_cfg.num_ports; port_id++) {
+ set_sym_hash_per_port(conn, port_id);
+ set_hash_global_config(conn, port_id, flow_type,
+ "simple_xor", "enable");
+ }
+
+ for (port_id = 0; port_id < current_cfg.num_ports; port_id+=2) {
+ set_hash_input_set_4(conn, port_id, flow_type, field0, field1,
+ field2, field3, "add");
+ }
+ }
+ flow_dir_cfg = 1;
+ return 1;
+}
+
+void get_swq_offset(uint8_t start, uint8_t num, char *buf)
+{
+ int i;
+ uint32_t len = 0;
+
+ for (i = start; i < start+num; i++) {
+ sprintf(buf + len, "SWQ%d ", i);
+ len = strlen(buf);
+ }
+}
+
+void get_swq(uint8_t num, char *buf)
+{
+ int i;
+ uint32_t len = 0;
+
+ for (i=0;i<num;i++) {
+ sprintf(buf + len, "SWQ%d ", swq_index++);
+ len = strlen(buf);
+ }
+}
+
+void get_prv_to_pub_map(char *buf)
+{
+ int j;
+ uint32_t len = 0;
+ for (j = 0; j < current_cfg.num_ports; j+=2) {
+ sprintf(buf + len, "(%d,%d)", j, j+1);
+ len = strlen(buf);
+ }
+}
+
+void get_prv_que_handler(char *buf)
+{
+ int j;
+ uint32_t len = 0;
+ sprintf(buf + len, "(");
+ len = strlen(buf);
+ for (j = 0; j < current_cfg.num_ports; j+=2) {
+ sprintf(buf + len, "%d,", j);
+ len = strlen(buf);
+ }
+ sprintf(buf + len, ")");
+}
+
+void get_txq(uint8_t start_q, uint8_t queue_num, uint8_t ports, char *buf)
+{
+ int i, j;
+ uint32_t len = 0;
+ for (i=tx_start_port;i<tx_start_port + ports;i+=2)
+ {
+ for (j=start_q;j<(start_q + queue_num);j++)
+ {
+ sprintf(buf + len, " TXQ%d.%d TXQ%d.%d", i, j, i+1, j);
+ len = strlen(buf);
+ }
+ }
+
+}
+
+void get_rxq(uint8_t start_q, uint8_t queue_num, uint8_t ports, char *buf)
+{
+ int i, j;
+ uint32_t len = 0;
+
+ for (i=rx_start_port;i<rx_start_port + ports;i+=2)
+ {
+ for (j=start_q;j<(start_q + queue_num);j++)
+ {
+ sprintf(buf + len, " RXQ%d.%d RXQ%d.%d", i, j, i+1, j);
+ len = strlen(buf);
+ }
+ }
+
+}
+
+struct mg_context *
+rest_api_init(struct app_params *app)
+{
+ struct rte_cfgfile *tcfg;
+ FILE *f;
+ char buf[256];
+ const char *options[] = {"listening_ports", "80", NULL};
+ uint32_t i, lcore_id = 0;
+ uint32_t sock, index;
+
+ /* Server context handle */
+ rapp = app;
+
+ for (lcore_id=0;lcore_id<64;lcore_id++) {
+ //lcore_id = rte_get_next_lcore(lcore_id, 0, 0);
+ sock = eal_cpu_socket_id(lcore_id);
+ index = (sock == 0)? sock0++ : sock1++;
+ sock_cpus[sock][index] = lcore_id;
+ }
+
+
+ /* Initialize the icivetweb library */
+ mg_init_library(0);
+
+ /* Start the server */
+ ctx = mg_start(NULL, 0, options);
+ if (ctx == NULL) {
+ printf("REST server did not start\n");
+ printf("REST services will not be supported.. Try again ");
+ printf("by disabling other webservers\n");
+ goto end;
+ }
+
+ /* init handlers being called here */
+ init_stat_cfg();
+
+ /* static config handler */
+ mg_set_request_handler(ctx, "/vnf", vnf_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config", static_cfg_handler, 0);
+
+ /* arp handler */
+ mg_set_request_handler(ctx, "/vnf/config/arp", arp_handler, 0);
+
+ /* route handler */
+ mg_set_request_handler(ctx, "/vnf/config/route", route_handler, 0);
+
+
+ /* link related handlers */
+ mg_set_request_handler(ctx, "/vnf/config/link", link_handler, 0);
+ //mg_set_request_handler(ctx, "/vnf/config/link/*", linkid_handler, 0);
+
+ /* dbg related handlers */
+ mg_set_request_handler(ctx, "/vnf/config/dbg", dbg_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/dbg/pipelines", dbg_pipelines_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/dbg/cmd", dbg_cmd_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/dbg/run", dbg_run_handler, 0);
+
+ mg_set_request_handler(ctx, "/vnf/quit", cmd_quit_handler, 0);
+
+ printf("Waiting for config input for 30 secs\n");
+ index = 0;
+ while(1) {
+ if (post_not_received == 0 || (index == 30))
+ break;
+ sleep(1);
+ index++;
+ }
+
+ if (index == 30 && (post_not_received != 0))
+ printf("Input not received for 30 secs, going with default");
+
+ const char *name = "vnf_template.txt";
+ /* Load application configuration file */
+ tcfg = rte_cfgfile_load(name, 0);
+ if (tcfg == NULL)
+ printf("File could not be loaded\n");
+
+// if (!current_cfg.sw_lb)
+// current_cfg.num_lb = 1;
+
+ /* build pipelines based on the input given */
+ build_pipeline();
+
+ for (i = 0; i < num_pipelines; i++) {
+ sprintf(buf, "/vnf/config/dbg/pipelines/%d", i);
+ mg_set_request_handler(ctx, buf, dbg_pipelines_id_handler, (void *)&i);
+ }
+
+ /* create a file for writing the config */
+ if (!current_cfg.sw_lb) {
+ mg_set_request_handler(ctx, "/vnf/flowdirector", flow_director_handler, 0);
+ sprintf(buf, "%s_%s_%dP_%dT.cfg", current_cfg.vnf_type, "HWLB",
+ current_cfg.num_ports, current_cfg.num_workers);
+ } else
+ sprintf(buf, "%s_%s_%dP_%dLB_%dT.cfg", current_cfg.vnf_type, "SWLB",
+ current_cfg.num_ports, current_cfg.num_lb, current_cfg.num_workers);
+
+ /* create a file which is more readable */
+ f = fopen(buf, "w");
+
+ print_to_file(f, tcfg);
+
+ app->config_file = strdup(buf);
+ app->parser_file = strdup(buf);
+
+ printf("Config file loaded :%s %s\n", app->config_file, traffic_type);
+
+end:
+ return ctx;
+}