summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>2017-09-25 03:36:02 +0530
committerDeepak S <deepak.s@linux.intel.com>2017-10-04 14:31:39 -0700
commitc65d2e761955affbdb76fc31ebb188ac492c31ca (patch)
tree35224c83fa80c0f6dd297c9cee52f5894ade3c56
parent74c5414a1fc7bc2e72c8b727dea974643f3c1bbe (diff)
REST_API: rest api client implementation
JIRA: SAMPLEVNF-78 This patch implements rest api's for VNF clients. This comprises of * vnf api's for common functionality * vnf api's for CGNAPT * vnf api's for VFW Change-Id: I56d22c64bf3ee5b0a2e536da8169ac7583499041 Signed-off-by: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
-rw-r--r--VNFs/UDP_Replay/main.c155
-rw-r--r--VNFs/vACL/Makefile10
-rw-r--r--VNFs/vACL/main.c18
-rw-r--r--VNFs/vACL/pipeline/pipeline_acl.c297
-rw-r--r--VNFs/vACL/pipeline/pipeline_acl.h4
-rw-r--r--VNFs/vACL/vnf_template.txt82
-rw-r--r--VNFs/vCGNAPT/Makefile7
-rw-r--r--VNFs/vCGNAPT/init.c1
-rw-r--r--VNFs/vCGNAPT/main.c18
-rw-r--r--VNFs/vCGNAPT/pipeline/pipeline_cgnapt.c226
-rw-r--r--VNFs/vCGNAPT/pipeline/pipeline_cgnapt.h8
-rw-r--r--VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c110
-rw-r--r--VNFs/vCGNAPT/pipeline/pipeline_cgnapt_common.h4
-rw-r--r--VNFs/vCGNAPT/vnf_template.txt80
-rw-r--r--VNFs/vFW/Makefile6
-rw-r--r--VNFs/vFW/init.c2
-rw-r--r--VNFs/vFW/main.c19
-rw-r--r--VNFs/vFW/pipeline/pipeline_vfw.c478
-rw-r--r--VNFs/vFW/pipeline/pipeline_vfw.h15
-rw-r--r--VNFs/vFW/vnf_template.txt82
-rw-r--r--common/VIL/l2l3_stack/lib_arp.c19
-rw-r--r--common/VIL/l2l3_stack/lib_arp.h20
-rw-r--r--common/VIL/l2l3_stack/tsx.h6
-rw-r--r--common/VIL/pipeline_arpicmp/pipeline_arpicmp.c17
-rw-r--r--common/VIL/pipeline_common/pipeline_common_fe.c4
-rw-r--r--common/VIL/pipeline_master/pipeline_master_be.c4
-rw-r--r--common/vnf_common/app.h16
-rw-r--r--common/vnf_common/config_parse.c10
-rw-r--r--common/vnf_common/rest_api.c2448
-rwxr-xr-xtools/vnf_build.sh25
30 files changed, 3962 insertions, 229 deletions
diff --git a/VNFs/UDP_Replay/main.c b/VNFs/UDP_Replay/main.c
index 56513c1b..587057fc 100644
--- a/VNFs/UDP_Replay/main.c
+++ b/VNFs/UDP_Replay/main.c
@@ -201,6 +201,7 @@ cmdline_parse_ctx_t main_ctx[];
uint32_t timer_lcore;
uint32_t exit_loop = 1;
port_config_t *port_config;
+
#define MEMPOOL_SIZE 32 * 1024
#define BUFFER_SIZE 2048
#define CACHE_SIZE 256
@@ -437,160 +438,6 @@ app_link_down_internal(__rte_unused struct app_params *app, struct app_link_para
cp->state = 0;
}
-/* int
- * inet_pton_ipv4(src, dst)
- * like inet_aton() but without all the hexadecimal and shorthand.
- * return:
- * 1 if `src' is a valid dotted quad, else 0.
- * notice:
- * does not touch `dst' unless it's returning 1.
- * author:
- * Paul Vixie, 1996.
- */
-static int inet_pton_ipv4(const char *src, unsigned char *dst)
-{
- static const char digits[] = "0123456789";
- int saw_digit, octets, ch;
- unsigned char tmp[INADDRSZ], *tp;
- saw_digit = 0;
- octets = 0;
- *(tp = tmp) = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
- if ((pch = strchr(digits, ch)) != NULL) {
- unsigned int new = *tp * 10 + (pch - digits);
- if (new > 255)
- return 0;
- if (!saw_digit) {
- if (++octets > 4)
- return 0;
- saw_digit = 1;
- }
- *tp = (unsigned char)new;
- } else if (ch == '.' && saw_digit) {
- if (octets == 4)
- return 0;
- *++tp = 0;
- saw_digit = 0;
- } else
- return 0;
- }
- if (octets < 4)
- return 0;
- memcpy(dst, tmp, INADDRSZ);
- return 1;
-}
-
-/* int
- * inet_pton_ipv6(src, dst)
- * convert presentation level address to network order binary form.
- * return:
- * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
- * notice:
- * (1) does not touch `dst' unless it's returning 1.
- * (2) :: in a full address is silently ignored.
- * credit:
- * inspired by Mark Andrews.
- * author:
- * Paul Vixie, 1996.
- */
-static int inet_pton_ipv6(const char *src, unsigned char *dst)
-{
- static const char xdigits_l[] = "0123456789abcdef",
- xdigits_u[] = "0123456789ABCDEF";
- unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
- const char *xdigits = 0, *curtok = 0;
- int ch = 0, saw_xdigit = 0, count_xdigit = 0;
- unsigned int val = 0;
- unsigned dbloct_count = 0;
- memset((tp = tmp), '\0', IN6ADDRSZ);
- endp = tp + IN6ADDRSZ;
- colonp = NULL;
- if (*src == ':')
- if (*++src != ':')
- return 0;
- curtok = src;
- saw_xdigit = count_xdigit = 0;
- val = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
- if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
- pch = strchr((xdigits = xdigits_u), ch);
- if (pch != NULL) {
- if (count_xdigit >= 4)
- return 0;
- val <<= 4;
- val |= (pch - xdigits);
- if (val > 0xffff)
- return 0;
- saw_xdigit = 1;
- count_xdigit++;
- continue;
- }
- if (ch == ':') {
- curtok = src;
- if (!saw_xdigit) {
- if (colonp)
- return 0;
- colonp = tp;
- continue;
- } else if (*src == '\0') {
- return 0;
- }
- if (tp + sizeof(int16_t) > endp)
- return 0;
- *tp++ = (unsigned char)((val >> 8) & 0xff);
- *tp++ = (unsigned char)(val & 0xff);
- saw_xdigit = 0;
- count_xdigit = 0;
- val = 0;
- dbloct_count++;
- continue;
- }
- if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
- inet_pton_ipv4(curtok, tp) > 0) {
- tp += INADDRSZ;
- saw_xdigit = 0;
- dbloct_count += 2;
- break; /* '\0' was seen by inet_pton4(). */
- }
- return 0;
- }
- if (saw_xdigit) {
- if (tp + sizeof(int16_t) > endp)
- return 0;
- *tp++ = (unsigned char)((val >> 8) & 0xff);
- *tp++ = (unsigned char)(val & 0xff);
- dbloct_count++;
- }
- if (colonp != NULL) {
- if (dbloct_count == 8)
- return 0;
- const int n = tp - colonp;
- int i;
- for (i = 1; i <= n; i++) {
- endp[-i] = colonp[n - i];
- colonp[n - i] = 0;
- }
- tp = endp;
- }
- if (tp != endp)
- return 0;
- memcpy(dst, tmp, IN6ADDRSZ);
- return 1;
-}
-static int my_inet_pton_ipv6(int af, const char *src, void *dst)
-{
- switch (af) {
- case AF_INET:
- return inet_pton_ipv4(src, dst);
- case AF_INET6:
- return inet_pton_ipv6(src, dst);
- default:
- errno = EAFNOSUPPORT;
- return -1;
- }
-}
void convert_ipstr_to_numeric(void)
{
uint32_t i;
diff --git a/VNFs/vACL/Makefile b/VNFs/vACL/Makefile
index bba5a6bc..0995f905 100644
--- a/VNFs/vACL/Makefile
+++ b/VNFs/vACL/Makefile
@@ -30,7 +30,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
# binary name
APP = vACL
-
VPATH += $(VNF_CORE)/common/vnf_common
VPATH += $(VNF_CORE)/common/VIL/conntrack
VPATH += $(VNF_CORE)/common/VIL/pipeline_common
@@ -54,7 +53,7 @@ INC += $(wildcard $(VNF_CORE)/common/VIL/pipeline_master/*.h)
INC += $(wildcard $(VNF_CORE)/common/VIL/pipeline_passthrough/*.h)
INC += $(wildcard $(VNF_CORE)/common/VIL/pipeline_txrx/*.h)
INC += $(wildcard $(VNF_CORE)/common/VIL/l2l3_stack/*.h)
-INC += $(wildcard $(VNF_CORE)/common/VIL/gateway/*.h
+INC += $(wildcard $(VNF_CORE)/common/VIL/gateway/*.h)
CFLAGS += -I$(SRCDIR) -mrtm -mhle -I$(SRCDIR)/pipeline -I$(VNF_CORE)/common/vnf_common
CFLAGS += -I$(VNF_CORE)/common/VIL/l2l3_stack -I$(VNF_CORE)/common/VIL/conntrack
@@ -64,9 +63,16 @@ CFLAGS += -I$(VNF_CORE)/common/VIL/pipeline_txrx
CFLAGS += -I$(VNF_CORE)/common/VIL/pipeline_arpicmp
CFLAGS += -I$(VNF_CORE)/common/VIL/gateway
+TOP = $(RTE_SDK)/../civetweb
+CFLAGS += -I$(TOP)/include $(COPT) -DUSE_WEBSOCKET -DUSE_IPV6 -DUSE_SSL_DH=1
+CFLAGS += -DREST_API_SUPPORT
+LDFLAGS += -ljson -lcrypto -lssl
+LDFLAGS += -L$(RTE_SDK)/../civetweb/ -lcivetweb
+
# all source are stored in SRCS-y
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rest_api.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/VNFs/vACL/main.c b/VNFs/vACL/main.c
index 9ebf6fc3..a6ba00b6 100644
--- a/VNFs/vACL/main.c
+++ b/VNFs/vACL/main.c
@@ -15,12 +15,14 @@
*/
#include "app.h"
+#include "pipeline_acl.h"
static struct app_params app;
int
main(int argc, char **argv)
{
+ struct mg_context *ctx = NULL;
rte_openlog_stream(stderr);
/* Config */
@@ -28,6 +30,12 @@ main(int argc, char **argv)
app_config_args(&app, argc, argv);
+ if (is_rest_support()) {
+ /* initialize the rest api */
+ set_vnf_type("VACL");
+ ctx = rest_api_init(&app);
+ }
+
app_config_preproc(&app);
app_config_parse(&app, app.parser_file);
@@ -40,11 +48,21 @@ main(int argc, char **argv)
/* Init */
app_init(&app);
+ if (is_rest_support() && (ctx != NULL)) {
+ /* rest api's for cgnapt */
+ rest_api_acl_init(ctx, &app);
+ }
+
/* Run-time */
rte_eal_mp_remote_launch(
app_thread,
(void *) &app,
CALL_MASTER);
+ if (is_rest_support() && (ctx != NULL)) {
+ mg_stop(ctx);
+ printf("Civet server stopped.\n");
+ }
+
return 0;
}
diff --git a/VNFs/vACL/pipeline/pipeline_acl.c b/VNFs/vACL/pipeline/pipeline_acl.c
index 1a4ed4f5..f1935622 100644
--- a/VNFs/vACL/pipeline/pipeline_acl.c
+++ b/VNFs/vACL/pipeline/pipeline_acl.c
@@ -49,6 +49,13 @@
#include "pipeline_acl_be.h"
#include "rte_cnxn_tracking.h"
+int acl_load_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int acl_clear_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int acl_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+uint32_t rules_loaded = 0;
+extern struct cmdline *pipe_cl;
+struct app_params *myapp;
+
/**
* A structure defining the ACL rule for the TAILQ Tables.
*/
@@ -4176,3 +4183,293 @@ struct pipeline_type pipeline_acl = {
.be_ops = &pipeline_acl_be_ops,
.fe_ops = &pipeline_acl_fe_ops,
};
+
+void all_acl_stats(struct mg_connection *conn)
+{
+
+ struct app_params *app = myapp;
+ int i, j;
+ struct rte_ACL_counter_block acl_counter_sums;
+ struct rte_CT_counter_block ct_counter_sums;
+ struct rte_CT_counter_block *ct_counters;
+ struct action_counter_block action_counter_sum[action_array_max];
+
+ memset(&acl_counter_sums, 0, sizeof(acl_counter_sums));
+ memset(&ct_counter_sums, 0, sizeof(ct_counter_sums));
+
+ 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, "ACL Stats\n");
+ for (i = 0; i <= rte_ACL_hi_counter_block_in_use; i++) {
+ struct rte_ACL_counter_block *acl_ctrs =
+ &rte_acl_counter_table[i];
+ ct_counters = rte_acl_counter_table[i].ct_counters;
+ mg_printf(conn, "acl entry[%i] tpkts_processed: %" PRIu64
+ ", pkts_drop: %" PRIu64 ", pkts_received: %" PRIu64
+ ", bytes_processed: %" PRIu64 "\n", i,
+ acl_ctrs->tpkts_processed, acl_ctrs->pkts_drop,
+ acl_ctrs->pkts_received, acl_ctrs->bytes_processed);
+
+ acl_counter_sums.tpkts_processed += acl_ctrs->tpkts_processed;
+ acl_counter_sums.bytes_processed += acl_ctrs->bytes_processed;
+ acl_counter_sums.pkts_drop += acl_ctrs->pkts_drop;
+ acl_counter_sums.pkts_received += acl_ctrs->pkts_received;
+ ct_counter_sums.pkts_forwarded += ct_counters->pkts_forwarded;
+ ct_counter_sums.pkts_drop += ct_counters->pkts_drop;
+ }
+
+ mg_printf(conn, "ACL TOTAL: tpkts_processed: %" PRIu64 ", pkts_drop: %" PRIu64
+ ", pkts_received: %" PRIu64 ", bytes_processed: %" PRIu64 "\n\n",
+ acl_counter_sums.tpkts_processed,
+ acl_counter_sums.pkts_drop,
+ acl_counter_sums.pkts_received,
+ acl_counter_sums.bytes_processed);
+
+ mg_printf(conn, "CT TOTAL: ct_packets_forwarded: %" PRIu64
+ ", ct_packets_dropped: %" PRIu64 "\n\n",
+ ct_counter_sums.pkts_forwarded, ct_counter_sums.pkts_drop);
+
+ for (i = 0; i <= rte_ACL_hi_counter_block_in_use; i++) {
+ for (j = 0; j < action_array_max; j++) {
+ if (action_array_active[j].action_bitmap &
+ acl_action_count) {
+ action_counter_sum[j].packetCount +=
+ action_counter_table[i][j].packetCount;
+ action_counter_sum[j].byteCount +=
+ action_counter_table[i][j].byteCount;
+ }
+ }
+ }
+
+ for (j = 0; j < action_array_max; j++) {
+ if (action_array_active[j].action_bitmap & acl_action_count)
+ mg_printf(conn, "Action ID: %02u, packetCount: %" PRIu64
+ ", byteCount: %" PRIu64 "\n", j,
+ action_counter_sum[j].packetCount,
+ action_counter_sum[j].byteCount);
+ }
+ mg_printf(conn, "<p>Command Passed</p>");
+ mg_printf(conn, "</body></html>\n");
+}
+
+int acl_stats_handler(struct mg_connection *conn, void *cbdata)
+{
+ uint32_t num_links = 0, len = 0;
+ char buf[1024];
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+ struct app_params *app = myapp;
+ int i;
+
+ if (!strcmp(ri->request_method, "GET")) {
+ all_acl_stats(conn);
+ mg_printf(conn, "%s\n", &buf[0]);
+ 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 GET handler\n",
+ ri->request_method);
+ }
+
+ for (i = 0; i <= rte_ACL_hi_counter_block_in_use; i++) {
+ rte_acl_counter_table[i].tpkts_processed = 0;
+ rte_acl_counter_table[i].bytes_processed = 0;
+ rte_acl_counter_table[i].pkts_drop = 0;
+ rte_acl_counter_table[i].pkts_received = 0;
+ rte_acl_counter_table[i].pkts_drop_ttl = 0;
+ rte_acl_counter_table[i].pkts_drop_bad_size = 0;
+ rte_acl_counter_table[i].pkts_drop_fragmented = 0;
+ rte_acl_counter_table[i].pkts_drop_without_arp_entry = 0;
+ rte_acl_counter_table[i].ct_counters->pkts_forwarded = 0;
+ rte_acl_counter_table[i].ct_counters->pkts_drop = 0;
+ }
+
+ memset(&action_counter_table, 0, sizeof(action_counter_table));
+
+ mg_printf(conn, "%s\n", &buf[0]);
+ return 1;
+
+}
+
+int acl_version_handler(struct mg_connection *conn, void *cbdata)
+{
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+
+ 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, "<p>Command Passed</p>");
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+int acl_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ if (strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Only GET method allowed");
+ 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, "<h2> These are the methods that are supported </h2>");
+ mg_printf(conn, "<h3> /load </h3>");
+ mg_printf(conn, "<h3> /clear </h3>");
+ mg_printf(conn, "<html><body>");
+
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+static int acl_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);
+ mg_printf(conn, "Inside vfw_field_found %s \n", filename);
+
+ if (filename && *filename) {
+ snprintf(path, pathlen, "/tmp/%s", filename);
+ struct app_params *app = myapp;
+ int status;
+ int fd;
+
+ mg_printf(conn, "path: %s\n", path);
+
+ /* Make sure the file exists before clearing rules and actions */
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ mg_printf(conn, "Cannot open file \"%s\"\n", filename);
+ return FORM_FIELD_STORAGE_GET;
+ }
+ close(fd);
+
+ return FORM_FIELD_STORAGE_STORE;
+ }
+
+ return FORM_FIELD_STORAGE_GET;
+}
+
+static int acl_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;
+}
+
+static int acl_field_stored(const char *path, long long file_size,
+ void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+ int status;
+
+ mg_printf(conn,
+ "stored as %s (%lu bytes)\r\n\r\n",
+ path,
+ (unsigned long)file_size);
+
+ /* Clear all rules and actions */
+ status = app_pipeline_acl_clearrules(myapp);
+
+ if (status != 0) {
+ mg_printf(conn, "Command failed\n");
+ return 1;
+ }
+
+ /* Process commands in script file */
+ app_loadrules_file(pipe_cl->ctx, path);
+ rules_loaded = 1;
+
+ return 0;
+}
+
+int acl_load_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ int ret;
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ struct mg_form_data_handler fdh = {acl_field_found, acl_field_get,
+ acl_field_stored, 0};
+
+ /* 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: "
+ "text/plain\r\nConnection: close\r\n\r\n");
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Rule file is %s\n", rules_loaded? "LOADED":"NOT LOADED");
+ }
+
+ 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_printf(conn, "Form data:");
+ ret = mg_handle_form_request(conn, &fdh);
+ mg_printf(conn, "\r\n%i fields found", ret);
+
+ return 1;
+}
+
+int acl_clear_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ struct app_params *app = myapp;
+ int status;
+ 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>");
+ status = app_pipeline_acl_clearrules(app);
+
+ if (status != 0) {
+ mg_printf(conn, "Command failed\n");
+ return 1;
+ }
+
+ mg_printf(conn, "Command Success\n");
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+}
+
+void rest_api_acl_init(struct mg_context *ctx, struct app_params *app)
+{
+ myapp = app;
+
+ /* vCGNAPT commands */
+ mg_set_request_handler(ctx, "/vnf/config/rules", acl_rules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/rules/load", acl_load_rules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/rules/clear", acl_clear_rules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/status", acl_version_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/stats", acl_stats_handler, 0);
+
+}
diff --git a/VNFs/vACL/pipeline/pipeline_acl.h b/VNFs/vACL/pipeline/pipeline_acl.h
index 80a85cae..93b92c45 100644
--- a/VNFs/vACL/pipeline/pipeline_acl.h
+++ b/VNFs/vACL/pipeline/pipeline_acl.h
@@ -28,6 +28,8 @@
#include "pipeline.h"
#include "pipeline_acl_be.h"
+#include <civetweb.h>
+#include <json/json.h>
/* ACL IPV4 and IPV6 enable flags for debugging (Default both on) */
extern int acl_ipv4_enabled;
@@ -47,6 +49,8 @@ extern void *acl_rule_table_ipv6_standby;
#define acl_delete_command 1
#define IPV6_32BIT_LENGTH 4
+void rest_api_acl_init(struct mg_context *ctx, struct app_params *app);
+
/**
* Add ACL rule to the ACL rule table.
* Rules are added standby table.
diff --git a/VNFs/vACL/vnf_template.txt b/VNFs/vACL/vnf_template.txt
new file mode 100644
index 00000000..ed8253be
--- /dev/null
+++ b/VNFs/vACL/vnf_template.txt
@@ -0,0 +1,82 @@
+[MASTER]
+type = MASTER
+core = 0
+
+[ARPICMP]
+type = ARPICMP
+core = 1
+pktq_in = SWQ0
+pktq_out = TXQ0.0 TXQ1.0
+pktq_in_prv = RXQ0.0
+prv_to_pub_map = (0,1)
+prv_que_handler = (0)
+
+[TIMER]
+type = TIMER
+core = 2
+n_flows = 1048576
+
+[TXRX-BEGIN]
+type = TXRX
+core = 2
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = SWQ0 SWQ1 SWQ2
+pipeline_txrx_type = RXRX
+dest_if_offset=176
+
+[TXRX-END]
+type = TXRX
+core = 5
+pktq_in = SWQ5 SWQ6
+pktq_out = TXQ0.1 TXQ1.1
+pipeline_txrx_type = TXTX
+
+[LOADB]
+type = LOADB
+core = 3
+pktq_in = SWQ0 SWQ1
+pktq_out = SWQ3 SWQ4
+outport_offset = 136
+phyport_offset = 204
+n_vnf_threads = 1
+prv_que_handler = (0)
+
+[VACL]
+type = ACL
+core = 4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ5 SWQ6
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+
+[VCGNAPT]
+type = CGNAPT
+core = 3
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = TXQ0.1 TXQ1.1 SWQ0
+phyport_offset = 204
+n_flows = 1048576
+key_offset = 192;64
+key_size = 8
+hash_offset = 200;72
+timer_period = 100
+max_clients_per_ip = 65535
+max_port_per_client = 10
+public_ip_port_range = 98103214:(1, 65535)
+vnf_set = (3,4,5)
+pkt_type = ipv4
+cgnapt_meta_offset = 128
+prv_que_handler = (0,)
+
+[VFW]
+type = VFW
+core = s0c4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ7 SWQ8;TXQ0.0 TXQ1.0
+n_rules = 10000
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+tcp_time_wait = 10
+
diff --git a/VNFs/vCGNAPT/Makefile b/VNFs/vCGNAPT/Makefile
index a6feb730..41cacfb7 100644
--- a/VNFs/vCGNAPT/Makefile
+++ b/VNFs/vCGNAPT/Makefile
@@ -65,9 +65,16 @@ CFLAGS += -I$(VNF_CORE)/common/VIL/pipeline_txrx -I$(VNF_CORE)/common/VIL/alg
CFLAGS += -I$(VNF_CORE)/common/VIL/pipeline_arpicmp
CFLAGS += -I$(VNF_CORE)/common/VIL/gateway
+TOP = $(RTE_SDK)/../civetweb
+CFLAGS += -I$(TOP)/include $(COPT) -DUSE_WEBSOCKET -DUSE_IPV6 -DUSE_SSL_DH=1
+CFLAGS += -DREST_API_SUPPORT
+LDFLAGS += -ljson -lcrypto -lssl
+LDFLAGS += -L$(RTE_SDK)/../civetweb/ -lcivetweb
+
# all source are stored in SRCS-y
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rest_api.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/VNFs/vCGNAPT/init.c b/VNFs/vCGNAPT/init.c
index 76621d51..d61e419c 100644
--- a/VNFs/vCGNAPT/init.c
+++ b/VNFs/vCGNAPT/init.c
@@ -75,6 +75,7 @@ app_init_core_mask(struct app_params *app)
p->socket_id,
p->core_id,
p->hyper_th_id);
+ printf("lcore_id:%d\n", lcore_id);
if (lcore_id < 0)
rte_panic("Cannot create CPU core mask\n");
diff --git a/VNFs/vCGNAPT/main.c b/VNFs/vCGNAPT/main.c
index 9ebf6fc3..83fc37ff 100644
--- a/VNFs/vCGNAPT/main.c
+++ b/VNFs/vCGNAPT/main.c
@@ -15,12 +15,14 @@
*/
#include "app.h"
+#include "pipeline_cgnapt.h"
static struct app_params app;
int
main(int argc, char **argv)
{
+ struct mg_context *ctx = NULL;
rte_openlog_stream(stderr);
/* Config */
@@ -28,6 +30,12 @@ main(int argc, char **argv)
app_config_args(&app, argc, argv);
+ /* initialize the rest api */
+ if (is_rest_support()) {
+ set_vnf_type("VCGNAPT");
+ ctx = rest_api_init(&app);
+ }
+
app_config_preproc(&app);
app_config_parse(&app, app.parser_file);
@@ -40,11 +48,21 @@ main(int argc, char **argv)
/* Init */
app_init(&app);
+ if (is_rest_support() && (ctx != NULL)) {
+ /* rest api's for cgnapt */
+ rest_api_cgnapt_init(ctx, &app);
+ }
+
/* Run-time */
rte_eal_mp_remote_launch(
app_thread,
(void *) &app,
CALL_MASTER);
+ if (is_rest_support() && (ctx != NULL)) {
+ mg_stop(ctx);
+ printf("Civet server stopped.\n");
+ }
+
return 0;
}
diff --git a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.c b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.c
index fb0b95d1..0c6bf48d 100644
--- a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.c
+++ b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.c
@@ -29,6 +29,12 @@
#include <cmdline_parse_string.h>
#include <cmdline_parse_ipaddr.h>
#include <cmdline_parse_etheraddr.h>
+#include <cmdline_rdline.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include <fcntl.h>
+#include <unistd.h>
#include "app.h"
#include "pipeline_common_fe.h"
@@ -40,6 +46,8 @@
#include "cgnapt_pcp_fe.h"
#endif
+#define MAX_BUF_SIZE 2048
+
/**
* A structure defining the CG-NAPT entry that is stored on
* front end.
@@ -66,6 +74,12 @@ struct pipeline_cgnapt_t {
};
+int nat_load_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+int nat_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+uint32_t rules_loaded = 0;
+extern struct cmdline *pipe_cl;
+struct app_params *myapp;
+
/**
* Init function for CG-NAPT FE.
*
@@ -1405,7 +1419,8 @@ cmd_cgnapt_stats_parsed(
__rte_unused struct cmdline *cl,
__rte_unused void *data)
{
- all_cgnapt_stats();
+ char buf[2048];
+ all_cgnapt_stats(&buf[0]);
}
static cmdline_parse_token_string_t cmd_cgnapt_stats_p_string =
@@ -1457,7 +1472,8 @@ cmd_cgnapt_clear_stats_parsed(
__rte_unused struct cmdline *cl,
__rte_unused void *data)
{
- all_cgnapt_clear_stats();
+ char buf[2048];
+ all_cgnapt_clear_stats(&buf[0]);
}
static cmdline_parse_token_string_t cmd_cgnapt_clear_stats_p_string =
@@ -1475,6 +1491,212 @@ static cmdline_parse_token_string_t cmd_cgnapt_clear_stats_stats_string =
TOKEN_STRING_INITIALIZER(struct cmd_cgnapt_clear_stats_result, stats_string,
"stats");
+int cgnapt_stats_handler(struct mg_connection *conn, void *cbdata)
+{
+ uint32_t num_links = 0, len = 0;
+ char buf[1024];
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+ struct app_params *app = myapp;
+ int i;
+
+ if (!strcmp(ri->request_method, "GET")) {
+ all_cgnapt_stats(&buf[0]);
+ mg_printf(conn, "%s\n", &buf[0]);
+ 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 GET handler\n",
+ ri->request_method);
+ }
+
+ all_cgnapt_clear_stats(&buf[0]);
+ mg_printf(conn, "%s\n", &buf[0]);
+ return 1;
+
+}
+
+int cgnapt_cmd_ver_handler(struct mg_connection *conn, void *cbdata)
+{
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+
+ 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, "<p>Command Passed</p>");
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+/*
+ * loadrules
+ */
+
+/**
+ * Open file and process all commands in the file.
+ *
+ * @param ctx
+ * A pointer to the CLI context
+ * @param file_name
+ * A pointer to the file to process.
+ *
+ */
+static void cgnapt_loadrules_file(cmdline_parse_ctx_t *ctx, const char *file_name)
+{
+ struct cmdline *file_cl;
+ int fd;
+
+ fd = open(file_name, O_RDONLY);
+ if (fd < 0) {
+ printf("Cannot open file \"%s\"\n", file_name);
+ return;
+ }
+
+ file_cl = cmdline_new(ctx, "", fd, 1);
+ cmdline_interact(file_cl);
+ close(fd);
+}
+
+
+int nat_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ if (strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Only GET method allowed");
+ 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, "<h2> These are the methods that are supported </h2>");
+ mg_printf(conn, "<h3> /load </h3>");
+ mg_printf(conn, "<html><body>");
+
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+static int nat_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);
+ mg_printf(conn, "Inside vfw_field_found %s \n", filename);
+
+ if (filename && *filename) {
+ snprintf(path, pathlen, "/tmp/%s", filename);
+ struct app_params *app = myapp;
+ int status;
+ int fd;
+
+ mg_printf(conn, "path: %s\n", path);
+
+ /* Make sure the file exists before clearing rules and actions */
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ mg_printf(conn, "Cannot open file \"%s\"\n", filename);
+ return FORM_FIELD_STORAGE_GET;
+ }
+
+ close(fd);
+ return FORM_FIELD_STORAGE_STORE;
+ }
+
+ return FORM_FIELD_STORAGE_GET;
+}
+
+static int nat_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;
+}
+
+static int nat_field_stored(const char *path, long long file_size,
+ void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+ int status;
+
+ mg_printf(conn,
+ "stored as %s (%lu bytes)\r\n\r\n",
+ path,
+ (unsigned long)file_size);
+
+ /* Process commands in script file */
+ cgnapt_loadrules_file(pipe_cl->ctx, path);
+ rules_loaded = 1;
+
+ return 0;
+}
+
+int nat_load_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ int ret;
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ struct mg_form_data_handler fdh = {nat_field_found, nat_field_get,
+ nat_field_stored, 0};
+
+ /* 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: "
+ "text/plain\r\nConnection: close\r\n\r\n");
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Rule file is %s\n", rules_loaded? "LOADED":"NOT LOADED");
+ }
+
+ 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_printf(conn, "Form data:");
+ ret = mg_handle_form_request(conn, &fdh);
+ mg_printf(conn, "\r\n%i fields found", ret);
+
+ return 1;
+}
+
+void rest_api_cgnapt_init(struct mg_context *ctx, struct app_params *app)
+{
+ myapp = app;
+
+ /* vCGNAPT commands */
+ mg_set_request_handler(ctx, "/vnf/config/nat", nat_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/nat/load", nat_load_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/status", cgnapt_cmd_ver_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/stats", cgnapt_stats_handler, 0);
+
+}
+
static cmdline_parse_inst_t cmd_clear_stats = {
.f = cmd_cgnapt_clear_stats_parsed,
.data = NULL,
diff --git a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.h b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.h
index 5491648a..6497de27 100644
--- a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.h
+++ b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt.h
@@ -28,6 +28,8 @@
#include "pipeline.h"
#include "pipeline_cgnapt_common.h"
+#include <civetweb.h>
+#include <json/json.h>
/**
* Add NAPT rule to the NAPT rule table.
@@ -129,6 +131,12 @@ int
app_pipeline_cgnapt_nsp_del_entry(struct app_params *app,
uint32_t pipeline_id,
struct pipeline_cgnapt_nsp_t *nsp);
+#ifdef REST_API_SUPPORT
+/* REST api's are defined here */
+int cgnapt_cmd_ver_handler(struct mg_connection *conn, void *cbdata);
+int cgnapt_stats_handler(struct mg_connection *conn, void *cbdata);
+void rest_api_cgnapt_init(struct mg_context *ctx, struct app_params *app);
+#endif
/*
* Pipeline type
diff --git a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c
index f02fd164..f578587e 100644
--- a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c
+++ b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c
@@ -10469,9 +10469,9 @@ void *pipeline_cgnapt_msg_req_ver_handler(__rte_unused struct pipeline *p,
* Function to show CGNAPT stats
*
*/
-void all_cgnapt_stats(void)
+void all_cgnapt_stats(char *buf)
{
- int i;
+ int i, len = 0;
struct pipeline_cgnapt *p_nat;
uint64_t receivedPktCount = 0;
uint64_t missedPktCount = 0;
@@ -10481,7 +10481,7 @@ void all_cgnapt_stats(void)
uint64_t enaptedPktCount = 0;
uint64_t arpicmpPktCount = 0;
- printf("\nCG-NAPT Packet Stats:\n");
+ len += sprintf(buf + len, "\nCG-NAPT Packet Stats:\n");
for (i = 0; i < n_cgnapt_pipeline; i++) {
p_nat = all_pipeline_cgnapt[i];
@@ -10493,43 +10493,43 @@ void all_cgnapt_stats(void)
enaptedPktCount += p_nat->enaptedPktCount;
arpicmpPktCount += p_nat->arpicmpPktCount;
- printf("pipeline %d stats:\n", p_nat->pipeline_num);
- printf("Received %" PRIu64 ",", p_nat->receivedPktCount);
- printf("Missed %" PRIu64 ",", p_nat->missedPktCount);
- printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount);
- printf("Translated %" PRIu64 ",", p_nat->naptedPktCount);
- printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount);
- printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount);
- printf("arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount);
+ len += sprintf(buf + len, "pipeline %d stats:\n", p_nat->pipeline_num);
+ len += sprintf(buf + len, "Received %" PRIu64 ",", p_nat->receivedPktCount);
+ len += sprintf(buf + len, "Missed %" PRIu64 ",", p_nat->missedPktCount);
+ len += sprintf(buf + len, "Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount);
+ len += sprintf(buf + len, "Translated %" PRIu64 ",", p_nat->naptedPktCount);
+ len += sprintf(buf + len, "ingress %" PRIu64 ",", p_nat->inaptedPktCount);
+ len += sprintf(buf + len, "egress %" PRIu64 "\n", p_nat->enaptedPktCount);
+ len += sprintf(buf + len, "arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount);
#ifdef CGNAPT_DEBUGGING
- printf("\n Drop detail 1:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 1:%" PRIu64 ",",
p_nat->naptDroppedPktCount1);
- printf("\n Drop detail 2:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 2:%" PRIu64 ",",
p_nat->naptDroppedPktCount2);
- printf("\n Drop detail 3:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 3:%" PRIu64 ",",
p_nat->naptDroppedPktCount3);
- printf("\n Drop detail 4:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 4:%" PRIu64 ",",
p_nat->naptDroppedPktCount4);
- printf("\n Drop detail 5:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 5:%" PRIu64 ",",
p_nat->naptDroppedPktCount5);
- printf("\n Drop detail 6:%" PRIu64 "",
+ len += sprintf(buf + len, "\n Drop detail 6:%" PRIu64 "",
p_nat->naptDroppedPktCount6);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount1,
p_nat->missedpktcount2);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount3,
p_nat->missedpktcount4);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount5,
p_nat->missedpktcount6);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount7,
p_nat->missedpktcount8);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount9,
p_nat->missedpktcount10);
@@ -10537,32 +10537,35 @@ void all_cgnapt_stats(void)
}
- printf("\nTotal pipeline stats:\n");
- printf("Received %" PRIu64 ",", receivedPktCount);
- printf("Missed %" PRIu64 ",", missedPktCount);
- printf("Dropped %" PRIu64 ",", naptDroppedPktCount);
- printf("Translated %" PRIu64 ",", naptedPktCount);
- printf("ingress %" PRIu64 ",", inaptedPktCount);
- printf("egress %" PRIu64 "\n", enaptedPktCount);
- printf("arpicmp pkts %" PRIu64 "\n", arpicmpPktCount);
+ len += sprintf(buf + len, "\nTotal pipeline stats:\n");
+ len += sprintf(buf + len, "Received %" PRIu64 ",", receivedPktCount);
+ len += sprintf(buf + len, "Missed %" PRIu64 ",", missedPktCount);
+ len += sprintf(buf + len, "Dropped %" PRIu64 ",", naptDroppedPktCount);
+ len += sprintf(buf + len, "Translated %" PRIu64 ",", naptedPktCount);
+ len += sprintf(buf + len, "ingress %" PRIu64 ",", inaptedPktCount);
+ len += sprintf(buf + len, "egress %" PRIu64 "\n", enaptedPktCount);
+ len += sprintf(buf + len, "arpicmp pkts %" PRIu64 "\n", arpicmpPktCount);
+
+ if (!rest_api_supported())
+ printf("%s\n", buf);
}
-void all_cgnapt_clear_stats(void)
+void all_cgnapt_clear_stats(char *buf)
{
- int i;
+ int i, len = 0;
struct pipeline_cgnapt *p_nat;
- printf("\nCG-NAPT Packet Stats:\n");
+ len += sprintf(buf + len, "\nCG-NAPT Packet Stats:\n");
for (i = 0; i < n_cgnapt_pipeline; i++) {
p_nat = all_pipeline_cgnapt[i];
- printf("pipeline %d stats:\n", p_nat->pipeline_num);
- printf("Received %" PRIu64 ",", p_nat->receivedPktCount);
- printf("Missed %" PRIu64 ",", p_nat->missedPktCount);
- printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount);
- printf("Translated %" PRIu64 ",", p_nat->naptedPktCount);
- printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount);
- printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount);
- printf("arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount);
+ len += sprintf(buf + len, "pipeline %d stats:\n", p_nat->pipeline_num);
+ len += sprintf(buf + len, "Received %" PRIu64 ",", p_nat->receivedPktCount);
+ len += sprintf(buf + len, "Missed %" PRIu64 ",", p_nat->missedPktCount);
+ len += sprintf(buf + len, "Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount);
+ len += sprintf(buf + len, "Translated %" PRIu64 ",", p_nat->naptedPktCount);
+ len += sprintf(buf + len, "ingress %" PRIu64 ",", p_nat->inaptedPktCount);
+ len += sprintf(buf + len, "egress %" PRIu64 "\n", p_nat->enaptedPktCount);
+ len += sprintf(buf + len, "arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount);
p_nat->receivedPktCount = 0;
p_nat->missedPktCount = 0;
@@ -10573,38 +10576,41 @@ void all_cgnapt_clear_stats(void)
p_nat->arpicmpPktCount = 0;
#ifdef CGNAPT_DEBUGGING
- printf("\n Drop detail 1:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 1:%" PRIu64 ",",
p_nat->naptDroppedPktCount1);
- printf("\n Drop detail 2:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 2:%" PRIu64 ",",
p_nat->naptDroppedPktCount2);
- printf("\n Drop detail 3:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 3:%" PRIu64 ",",
p_nat->naptDroppedPktCount3);
- printf("\n Drop detail 4:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 4:%" PRIu64 ",",
p_nat->naptDroppedPktCount4);
- printf("\n Drop detail 5:%" PRIu64 ",",
+ len += sprintf(buf + len, "\n Drop detail 5:%" PRIu64 ",",
p_nat->naptDroppedPktCount5);
- printf("\n Drop detail 6:%" PRIu64 "",
+ len += sprintf(buf + len, "\n Drop detail 6:%" PRIu64 "",
p_nat->naptDroppedPktCount6);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount1,
p_nat->missedpktcount2);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount3,
p_nat->missedpktcount4);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount5,
p_nat->missedpktcount6);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount7,
p_nat->missedpktcount8);
- printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "",
+ len += sprintf(buf + len, "\nPkt_miss: %" PRIu64 " %" PRIu64 "",
p_nat->missedpktcount9,
p_nat->missedpktcount10);
#endif
}
+
+ if (!rest_api_supported())
+ printf("%s\n", buf);
}
/**
diff --git a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_common.h b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_common.h
index 4f4253cd..a7cd88a4 100644
--- a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_common.h
+++ b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_common.h
@@ -265,7 +265,7 @@ struct pipeline_cgnapt_entry_dbg_msg_req {
extern struct pipeline_be_ops pipeline_cgnapt_be_ops;
void print_num_ip_clients(void);
-void all_cgnapt_stats(void);
-void all_cgnapt_clear_stats(void);
+void all_cgnapt_stats(char *);
+void all_cgnapt_clear_stats(char *);
void print_static_cgnapt_entries(void);
#endif
diff --git a/VNFs/vCGNAPT/vnf_template.txt b/VNFs/vCGNAPT/vnf_template.txt
new file mode 100644
index 00000000..385c5312
--- /dev/null
+++ b/VNFs/vCGNAPT/vnf_template.txt
@@ -0,0 +1,80 @@
+[MASTER]
+type = MASTER
+core = 0
+
+[ARPICMP]
+type = ARPICMP
+core = 1
+pktq_in = SWQ0
+pktq_out = TXQ0.0 TXQ1.0
+pktq_in_prv = RXQ0.0
+prv_to_pub_map = (0,1)
+prv_que_handler = (0)
+
+[TIMER]
+type = TIMER
+core = 2
+n_flows = 1048576
+
+[TXRX-BEGIN]
+type = TXRX
+core = 2
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = SWQ0 SWQ1 SWQ2
+pipeline_txrx_type = RXRX
+dest_if_offset=176
+
+[TXRX-END]
+type = TXRX
+core = 5
+pktq_in = SWQ5 SWQ6
+pktq_out = TXQ0.1 TXQ1.1
+pipeline_txrx_type = TXTX
+
+[LOADB]
+type = LOADB
+core = 3
+pktq_in = SWQ0 SWQ1
+pktq_out = SWQ3 SWQ4
+outport_offset = 136
+phyport_offset = 204
+n_vnf_threads = 1
+prv_que_handler = (0)
+
+[VACL]
+type = ACL
+core = 4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ5 SWQ6
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+
+[VCGNAPT]
+type = CGNAPT
+core = 3
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = TXQ0.1 TXQ1.1 SWQ0
+phyport_offset = 204
+n_flows = 1048576
+key_offset = 192;64
+key_size = 8
+hash_offset = 200;72
+timer_period = 100
+max_clients_per_ip = 65535
+max_port_per_client = 10
+pkt_type = ipv4
+cgnapt_meta_offset = 128
+prv_que_handler = (0,)
+
+[VFW]
+type = VFW
+core = s0c4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ7 SWQ8;TXQ0.0 TXQ1.0
+n_rules = 10000
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+tcp_time_wait = 10
+
diff --git a/VNFs/vFW/Makefile b/VNFs/vFW/Makefile
index 1e79646d..b011eca2 100644
--- a/VNFs/vFW/Makefile
+++ b/VNFs/vFW/Makefile
@@ -66,9 +66,15 @@ CFLAGS += -I$(VNF_CORE)/common/VIL/acl
CFLAGS += -I$(VNF_CORE)/common/VIL/pipeline_arpicmp
CFLAGS += -I$(VNF_CORE)/common/VIL/gateway
+TOP = $(RTE_SDK)/../civetweb
+CFLAGS += -I$(TOP)/include $(COPT) -DUSE_WEBSOCKET -DUSE_IPV6 -DUSE_SSL_DH=1 -DREST_API_SUPPORT=1
+LDFLAGS += -ljson -lcrypto -lssl
+LDFLAGS += -L$(RTE_SDK)/../civetweb/ -lcivetweb
+
# all source are stored in SRCS-y
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rest_api.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/VNFs/vFW/init.c b/VNFs/vFW/init.c
index 4e98b335..0edc5e32 100644
--- a/VNFs/vFW/init.c
+++ b/VNFs/vFW/init.c
@@ -705,7 +705,7 @@ app_init_link(struct app_params *app)
port_config = rte_zmalloc(NULL, (app->n_links * size),
RTE_CACHE_LINE_SIZE);
if (port_config == NULL)
- rte_panic("port_config is NULL: Memory Allocation failure\n");
+ rte_panic("port_config is NULL: Memory Allocation failure num_links %d %d\n", app->n_links, app->n_links * size);
for (i = 0; i < app->n_links; i++) {
struct app_link_params *p_link = &app->link_params[i];
diff --git a/VNFs/vFW/main.c b/VNFs/vFW/main.c
index 9ebf6fc3..aec04ac5 100644
--- a/VNFs/vFW/main.c
+++ b/VNFs/vFW/main.c
@@ -15,12 +15,15 @@
*/
#include "app.h"
+#include <civetweb.h>
static struct app_params app;
+extern void rest_api_vfw_init(struct mg_context *ctx, struct app_params *app);
int
main(int argc, char **argv)
{
+ struct mg_context *ctx = NULL;
rte_openlog_stream(stderr);
/* Config */
@@ -28,6 +31,12 @@ main(int argc, char **argv)
app_config_args(&app, argc, argv);
+ if (is_rest_support()) {
+ /* initialize the rest api */
+ set_vnf_type("VFW");
+ ctx = rest_api_init(&app);
+ }
+
app_config_preproc(&app);
app_config_parse(&app, app.parser_file);
@@ -40,11 +49,21 @@ main(int argc, char **argv)
/* Init */
app_init(&app);
+ if (is_rest_support() && (ctx != NULL)) {
+ /* rest api's for cgnapt */
+ rest_api_vfw_init(ctx, &app);
+ }
+
/* Run-time */
rte_eal_mp_remote_launch(
app_thread,
(void *) &app,
CALL_MASTER);
+ if (is_rest_support() && (ctx != NULL)) {
+ mg_stop(ctx);
+ printf("Civet server stopped.\n");
+ }
+
return 0;
}
diff --git a/VNFs/vFW/pipeline/pipeline_vfw.c b/VNFs/vFW/pipeline/pipeline_vfw.c
index f235bc59..df94b5f7 100644
--- a/VNFs/vFW/pipeline/pipeline_vfw.c
+++ b/VNFs/vFW/pipeline/pipeline_vfw.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <sys/queue.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <rte_common.h>
#include <rte_hexdump.h>
@@ -45,10 +46,16 @@
#include "app.h"
#include "pipeline_common_fe.h"
+#include "pipeline_master.h"
#include "pipeline_vfw.h"
#include "pipeline_vfw_be.h"
#include "rte_cnxn_tracking.h"
+struct app_params *myapp;
+#define MAX_BUF_SIZE 2048
+extern struct cmdline *pipe_cl;
+extern int my_inet_pton_ipv6(int af, const char *src, void *dst);
+
/**
* A structure defining the VFW rule for the TAILQ Tables.
*/
@@ -4619,6 +4626,477 @@ cmdline_parse_token_num_t cmd_vfw_synproxy_flag =
TOKEN_NUM_INITIALIZER(struct cmd_vfw_synproxy_flag_result, synproxy_flag,
UINT8);
+static uint32_t rules_loaded;
+static int vfw_field_found(const char *key,
+ const char *filename,
+ char *path,
+ size_t pathlen,
+ void *user_data);
+
+static int vfw_field_get(const char *key, const char *value, size_t valuelen,
+ void *user_data);
+static int vfw_field_stored(const char *path, long long file_size, void *user_data);
+
+int vfw_clearrules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ struct app_params *app = myapp;
+ int status;
+ 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");
+
+ status = app_pipeline_vfw_clearrules(app);
+
+ if (status != 0) {
+ mg_printf(conn, "Command failed\n");
+ return 1;
+ }
+
+ mg_printf(conn, "Command Success\n");
+ return 1;
+}
+
+int vfw_clearstats_handler(__rte_unused struct mg_connection *conn,
+ __rte_unused void *cbdata)
+{
+ int i;
+ struct rte_CT_counter_block *ct_counters;
+
+ for (i = 0; i <= rte_VFW_hi_counter_block_in_use; i++) {
+ ct_counters = rte_vfw_counter_table[i].ct_counters;
+ rte_vfw_counter_table[i].bytes_processed = 0;
+ rte_vfw_counter_table[i].pkts_drop_without_rule = 0;
+ rte_vfw_counter_table[i].pkts_received = 0;
+ rte_vfw_counter_table[i].pkts_drop_ttl = 0;
+ rte_vfw_counter_table[i].pkts_drop_bad_size = 0;
+ rte_vfw_counter_table[i].pkts_drop_fragmented = 0;
+ rte_vfw_counter_table[i].pkts_drop_unsupported_type = 0;
+ rte_vfw_counter_table[i].pkts_drop_without_arp_entry = 0;
+ rte_vfw_counter_table[i].internal_time_sum = 0;
+ rte_vfw_counter_table[i].external_time_sum = 0;
+ rte_vfw_counter_table[i].time_measurements = 0;
+ rte_vfw_counter_table[i].ct_counters->pkts_forwarded = 0;
+ rte_vfw_counter_table[i].ct_counters->pkts_drop = 0;
+ rte_vfw_counter_table[i].pkts_fw_forwarded = 0;
+ rte_vfw_counter_table[i].pkts_acl_forwarded = 0;
+ ct_counters->current_active_sessions = 0;
+ ct_counters->sessions_activated = 0;
+ ct_counters->sessions_reactivated = 0;
+ ct_counters->sessions_established = 0;
+ ct_counters->sessions_closed = 0;
+ ct_counters->sessions_timedout = 0;
+ ct_counters->pkts_drop_invalid_conn = 0;
+ ct_counters->pkts_drop_invalid_state = 0;
+ ct_counters->pkts_drop_invalid_rst = 0;
+ ct_counters->pkts_drop_outof_window = 0;
+ }
+
+ memset(&action_counter_table, 0, sizeof(action_counter_table));
+ rte_vfw_reset_running_averages();
+ return 1;
+}
+
+int vfw_stats_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+ int i, j;
+ struct rte_VFW_counter_block vfw_counter_sums;
+ struct rte_CT_counter_block ct_counter_sums;
+ struct rte_CT_counter_block *ct_counters;
+ struct action_counter_block action_counter_sum[action_array_max];
+ uint64_t sum_pkts_drop_fw = 0;
+
+ if (!strcmp(ri->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, "Command Passed \n");
+ vfw_clearstats_handler(conn, cbdata);
+ mg_printf(conn, "</body></html>\n");
+ return 1;
+ }
+
+ if (strcmp(ri->request_method, "GET")) {
+ 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 GET handler\n",
+ ri->request_method);
+ return 1;
+ }
+
+ memset(&vfw_counter_sums, 0, sizeof(vfw_counter_sums));
+ memset(&ct_counter_sums, 0, sizeof(ct_counter_sums));
+
+ 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, "VFW Stats\n");
+ for (i = 0; i <= rte_VFW_hi_counter_block_in_use; i++) {
+ struct rte_VFW_counter_block *vfw_ctrs =
+ &rte_vfw_counter_table[i];
+ ct_counters = rte_vfw_counter_table[i].ct_counters;
+
+ uint64_t average_internal_time =
+ vfw_ctrs->time_measurements ==
+ 0 ? 0 : vfw_ctrs->internal_time_sum /
+ vfw_ctrs->time_measurements;
+ uint64_t average_external_time =
+ vfw_ctrs->time_measurements ==
+ 0 ? 0 : vfw_ctrs->external_time_sum /
+ vfw_ctrs->time_measurements;
+ uint64_t average_pkts_in_batch =
+ vfw_ctrs->num_pkts_measurements ==
+ 0 ? 0 : vfw_ctrs->num_batch_pkts_sum /
+ vfw_ctrs->num_pkts_measurements;
+ uint64_t pkts_drop_fw = vfw_ctrs->pkts_drop_ttl +
+ vfw_ctrs->pkts_drop_bad_size +
+ vfw_ctrs->pkts_drop_fragmented +
+ vfw_ctrs->pkts_drop_unsupported_type;
+
+ mg_printf(conn, "{\"VFW_counters\" : {\"id\" : \"%s\", \" pkts_received\": %"
+ PRIu64 ", \" pkts_fw_forwarded\": %"
+ PRIu64 ", \" pkts_drop_fw\": %"
+ PRIu64 ", \" pkts_acl_forwarded\": %"
+ PRIu64 ", \"pkts_drop_without_rule\" : %"
+ PRIu64 ", \"average_pkts_in_batch\" : %"
+ PRIu64 ", \"average_internal_time_in_clocks\" : %"
+ PRIu64 ", \"average_external_time_in_clocks\" : %"
+ PRIu64 ", \"total_time_measures\" : %"
+ PRIu32 ", \"ct_packets_forwarded\" : %"
+ PRIu64 ", \"ct_packets_dropped\" : %"
+ PRIu64 ", \"bytes_processed \": %"
+ PRIu64 ", \"ct_sessions\" : {"
+ "\"active\" : %" PRIu64 ", \"open_attempt\" : %"
+ PRIu64 ", \"re-open_attempt\" : %"
+ PRIu64 ", \"established\" : %"
+ PRIu64 ", \"closed\" : %"
+ PRIu64 ", \"timeout\" : %"
+ PRIu64 "}, \"ct_drops\" : {"
+ "\"out_of_window\" : %" PRIu64 ", \"invalid_conn\" : %"
+ PRIu64 ", \"invalid_state_transition\" : %"
+ PRIu64 " \"RST\" : %"
+ PRIu64 "}}\n",
+ vfw_ctrs->name,
+ vfw_ctrs->pkts_received,
+ vfw_ctrs->pkts_fw_forwarded,
+ pkts_drop_fw,
+ vfw_ctrs->pkts_acl_forwarded,
+ vfw_ctrs->pkts_drop_without_rule,
+ average_pkts_in_batch,
+ average_internal_time,
+ average_external_time,
+ vfw_ctrs->time_measurements,
+ ct_counters->pkts_forwarded,
+ ct_counters->pkts_drop,
+ vfw_ctrs->bytes_processed,
+ ct_counters->current_active_sessions,
+ ct_counters->sessions_activated,
+ ct_counters->sessions_reactivated,
+ ct_counters->sessions_established,
+ ct_counters->sessions_closed,
+ ct_counters->sessions_timedout,
+ ct_counters->pkts_drop_outof_window,
+ ct_counters->pkts_drop_invalid_conn,
+ ct_counters->pkts_drop_invalid_state,
+ ct_counters->pkts_drop_invalid_rst);
+
+ vfw_counter_sums.bytes_processed +=
+ vfw_ctrs->bytes_processed;
+
+ vfw_counter_sums.internal_time_sum +=
+ vfw_ctrs->internal_time_sum;
+ vfw_counter_sums.external_time_sum +=
+ vfw_ctrs->external_time_sum;
+ vfw_counter_sums.time_measurements +=
+ vfw_ctrs->time_measurements;
+
+ vfw_counter_sums.pkts_drop_ttl += vfw_ctrs->pkts_drop_ttl;
+ vfw_counter_sums.pkts_drop_bad_size +=
+ vfw_ctrs->pkts_drop_bad_size;
+ vfw_counter_sums.pkts_drop_fragmented +=
+ vfw_ctrs->pkts_drop_fragmented;
+ vfw_counter_sums.pkts_drop_unsupported_type +=
+ vfw_ctrs->pkts_drop_unsupported_type;
+ vfw_counter_sums.pkts_drop_without_arp_entry +=
+ vfw_ctrs->pkts_drop_without_arp_entry;
+
+ vfw_counter_sums.pkts_drop_without_rule +=
+ vfw_ctrs->pkts_drop_without_rule;
+ vfw_counter_sums.pkts_received += vfw_ctrs->pkts_received;
+ vfw_counter_sums.pkts_fw_forwarded +=
+ vfw_ctrs->pkts_fw_forwarded;
+ vfw_counter_sums.pkts_acl_forwarded +=
+ vfw_ctrs->pkts_acl_forwarded;
+ sum_pkts_drop_fw += pkts_drop_fw;
+ ct_counter_sums.pkts_forwarded += ct_counters->pkts_forwarded;
+ ct_counter_sums.pkts_drop += ct_counters->pkts_drop;
+ ct_counter_sums.current_active_sessions +=
+ ct_counters->current_active_sessions;
+ ct_counter_sums.sessions_activated +=
+ ct_counters->sessions_activated;
+ ct_counter_sums.sessions_reactivated +=
+ ct_counters->sessions_reactivated;
+ ct_counter_sums.sessions_established +=
+ ct_counters->sessions_established;
+ ct_counter_sums.sessions_closed += ct_counters->sessions_closed;
+ ct_counter_sums.sessions_timedout +=
+ ct_counters->sessions_timedout;
+ ct_counter_sums.pkts_drop_invalid_conn +=
+ ct_counters->pkts_drop_invalid_conn;
+ ct_counter_sums.pkts_drop_invalid_state +=
+ ct_counters->pkts_drop_invalid_state;
+ ct_counter_sums.pkts_drop_invalid_rst +=
+ ct_counters->pkts_drop_invalid_rst;
+ ct_counter_sums.pkts_drop_outof_window +=
+ ct_counters->pkts_drop_outof_window;
+
+ }
+
+ mg_printf(conn, "VFW TOTAL: pkts_received: %"
+ PRIu64 ", \"pkts_fw_forwarded\": %"
+ PRIu64 ", \"pkts_drop_fw\": %"
+ PRIu64 ", \"fw_drops\" : {"
+ "\"TTL_zero\" : %" PRIu64 ", \"bad_size\" : %"
+ PRIu64 ", \"fragmented_packet\" : %"
+ PRIu64 ", \"unsupported_packet_types\" : %"
+ PRIu64 ", \"no_arp_entry\" : %"
+ PRIu64 "}, \"pkts_acl_forwarded\": %"
+ PRIu64 ", \"pkts_drop_without_rule\": %"
+ PRIu64 ", \"packets_last_sec\" : %"
+ PRIu32 ", \"average_packets_per_sec\" : %"
+ PRIu32 ", \"bytes_last_sec\" : %"
+ PRIu32 ", \"average_bytes_per_sec\" : %"
+ PRIu32 ", \"bytes_processed \": %"
+ PRIu64 "\n",
+ vfw_counter_sums.pkts_received,
+ vfw_counter_sums.pkts_fw_forwarded,
+ sum_pkts_drop_fw,
+ vfw_counter_sums.pkts_drop_ttl,
+ vfw_counter_sums.pkts_drop_bad_size,
+ vfw_counter_sums.pkts_drop_fragmented,
+ vfw_counter_sums.pkts_drop_unsupported_type,
+ vfw_counter_sums.pkts_drop_without_arp_entry,
+ vfw_counter_sums.pkts_acl_forwarded,
+ vfw_counter_sums.pkts_drop_without_rule,
+ rte_vfw_performance_measures.pkts_last_second,
+ rte_vfw_performance_measures.ave_pkts_per_second,
+ rte_vfw_performance_measures.bytes_last_second,
+ rte_vfw_performance_measures.ave_bytes_per_second,
+ vfw_counter_sums.bytes_processed);
+
+ mg_printf(conn, "\"CT TOTAL: ct_packets_forwarded\" : %"
+ PRIu64 ", \" ct_packets_dropped\" : %"
+ PRIu64 ", \"ct_sessions\" : {"
+ "\"active\" : %" PRIu64 ", \"open_attempt\" : %"
+ PRIu64 ", \"re-open_attempt\" : %"
+ PRIu64 ", \"established\" : %"
+ PRIu64 ", \"closed\" : %"
+ PRIu64 ", \"timeout\" : %"
+ PRIu64 "}, \"ct_drops\" : {"
+ "\"out_of_window\" : %" PRIu64 ", \"invalid_conn\" : %"
+ PRIu64 ", \"invalid_state_transition\" : %"
+ PRIu64 " \"RST\" : %"
+ PRIu64 "}\n",
+ ct_counter_sums.pkts_forwarded,
+ ct_counter_sums.pkts_drop,
+ ct_counter_sums.current_active_sessions,
+ ct_counter_sums.sessions_activated,
+ ct_counter_sums.sessions_reactivated,
+ ct_counter_sums.sessions_established,
+ ct_counter_sums.sessions_closed,
+ ct_counter_sums.sessions_timedout,
+ ct_counter_sums.pkts_drop_outof_window,
+ ct_counter_sums.pkts_drop_invalid_conn,
+ ct_counter_sums.pkts_drop_invalid_state,
+ ct_counter_sums.pkts_drop_invalid_rst);
+
+ for (i = 0; i <= rte_VFW_hi_counter_block_in_use; i++) {
+ for (j = 0; j < action_array_max; j++) {
+ if (action_array_active[j].
+ action_bitmap & lib_acl_action_count) {
+ action_counter_sum[j].packetCount +=
+ action_counter_table[i][j].packetCount;
+ action_counter_sum[j].byteCount +=
+ action_counter_table[i][j].byteCount;
+ }
+ }
+ }
+
+ for (j = 0; j < action_array_max; j++) {
+ if (action_array_active[j].action_bitmap & lib_acl_action_count)
+ mg_printf(conn, "Action ID: %02u, packetCount: %" PRIu64
+ ", byteCount: %" PRIu64 "\n", j,
+ action_counter_sum[j].packetCount,
+ action_counter_sum[j].byteCount);
+ }
+ mg_printf(conn, "</body></html>");
+
+ return 1;
+
+}
+
+int vfw_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ if (strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Only GET method allowed");
+ 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, "<h2> These are the methods that are supported </h2>");
+ mg_printf(conn, "<h3> /load </h3>");
+ mg_printf(conn, "<h3> /clear </h3>");
+ mg_printf(conn, "<html><body>");
+
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+static int vfw_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);
+ mg_printf(conn, "Inside vfw_field_found %s \n", filename);
+
+ if (filename && *filename) {
+ snprintf(path, pathlen, "/tmp/%s", filename);
+ int fd;
+
+ mg_printf(conn, "path: %s\n", path);
+
+ /* Make sure the file exists before clearing rules and actions */
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ mg_printf(conn, "Cannot open file \"%s\"\n", filename);
+ return FORM_FIELD_STORAGE_GET;
+ }
+ close(fd);
+
+ return FORM_FIELD_STORAGE_STORE;
+ }
+
+ return FORM_FIELD_STORAGE_GET;
+}
+
+static int vfw_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;
+}
+
+static int vfw_field_stored(const char *path, long long file_size,
+ void *user_data)
+{
+ struct mg_connection *conn = (struct mg_connection *)user_data;
+ int status;
+
+ mg_printf(conn,
+ "stored as %s (%lu bytes)\r\n\r\n",
+ path,
+ (unsigned long)file_size);
+
+ /* Clear all rules and actions */
+ status = app_pipeline_vfw_clearrules(myapp);
+ if (status != 0) {
+ mg_printf(conn, "Command clearrules failed\n");
+ return 1;
+ }
+
+ /* Process commands in script file */
+ app_loadrules_file(pipe_cl->ctx, path);
+ rules_loaded = 1;
+
+ return 0;
+}
+
+int vfw_cmd_ver_handler(__rte_unused struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\nContent-Type: "
+ "text/plain\r\nConnection: close\r\n\r\n");
+ mg_printf(conn, "<html><body>");
+ mg_printf(conn, "<p>Command Passed</p>");
+ mg_printf(conn, "</body></html>\n");
+
+ return 1;
+}
+
+int vfw_load_rules_handler(struct mg_connection *conn, __rte_unused void *cbdata)
+{
+ /* Handler may access the request info using mg_get_request_info */
+ int ret;
+ const struct mg_request_info *req_info = mg_get_request_info(conn);
+ struct mg_form_data_handler fdh = {vfw_field_found, vfw_field_get,
+ vfw_field_stored, 0};
+
+ /* 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: "
+ "text/plain\r\nConnection: close\r\n\r\n");
+
+ if (!strcmp(req_info->request_method, "GET")) {
+ mg_printf(conn, "Rule file is %s\n", rules_loaded? "LOADED":"NOT LOADED");
+ }
+
+ 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_printf(conn, "Form data:");
+ ret = mg_handle_form_request(conn, &fdh);
+ mg_printf(conn, "\r\n%i fields found", ret);
+
+ //mg_handle_form_request(conn, &fdh);
+ //mg_printf(conn, "\r\n script file handled");
+ //rules_loaded = 1;
+
+ return 1;
+}
+
+void rest_api_vfw_init(struct mg_context *ctx, struct app_params *app)
+{
+ myapp = app;
+
+ /* vFW commands */
+ mg_set_request_handler(ctx, "/vnf/config/rules", vfw_rules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/rules/load", vfw_load_rules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/config/rules/clear", vfw_clearrules_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/stats", vfw_stats_handler, 0);
+ mg_set_request_handler(ctx, "/vnf/status", vfw_cmd_ver_handler, 0);
+
+}
+
cmdline_parse_inst_t cmd_vfw_synproxy = {
.f = cmd_vfw_synproxy_flag_parsed,
.data = NULL,
diff --git a/VNFs/vFW/pipeline/pipeline_vfw.h b/VNFs/vFW/pipeline/pipeline_vfw.h
index 3b1b25f0..96e7ad33 100644
--- a/VNFs/vFW/pipeline/pipeline_vfw.h
+++ b/VNFs/vFW/pipeline/pipeline_vfw.h
@@ -30,6 +30,9 @@
#include "app.h"
#include "pipeline_vfw_be.h"
+#include <civetweb.h>
+#include <json/json.h>
+
/* VFW IPV4 and IPV6 enable flags for debugging (Default both on) */
extern int vfw_ipv4_enabled;
extern int vfw_ipv6_enabled;
@@ -142,4 +145,16 @@ app_pipeline_action_delete(struct app_params *app,
extern struct pipeline_type pipeline_vfw;
+#ifdef REST_API_SUPPORT
+/* REST Api's defined here */
+int vfw_rules_handler(struct mg_connection *conn, void *cbdata);
+int vfw_load_rules_handler(struct mg_connection *conn, void *cbdata);
+int vfw_clearrules_handler(struct mg_connection *conn, void *cbdata);
+int vfw_stats_handler(struct mg_connection *conn, void *cbdata);
+int vfw_clearstats_handler(__rte_unused struct mg_connection *conn,
+ __rte_unused void *cbdata);
+int vfw_cmd_ver_handler(struct mg_connection *conn, __rte_unused void *cbdata);
+void rest_api_vfw_init(struct mg_context *ctx, struct app_params *app);
+#endif
+
#endif
diff --git a/VNFs/vFW/vnf_template.txt b/VNFs/vFW/vnf_template.txt
new file mode 100644
index 00000000..ed8253be
--- /dev/null
+++ b/VNFs/vFW/vnf_template.txt
@@ -0,0 +1,82 @@
+[MASTER]
+type = MASTER
+core = 0
+
+[ARPICMP]
+type = ARPICMP
+core = 1
+pktq_in = SWQ0
+pktq_out = TXQ0.0 TXQ1.0
+pktq_in_prv = RXQ0.0
+prv_to_pub_map = (0,1)
+prv_que_handler = (0)
+
+[TIMER]
+type = TIMER
+core = 2
+n_flows = 1048576
+
+[TXRX-BEGIN]
+type = TXRX
+core = 2
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = SWQ0 SWQ1 SWQ2
+pipeline_txrx_type = RXRX
+dest_if_offset=176
+
+[TXRX-END]
+type = TXRX
+core = 5
+pktq_in = SWQ5 SWQ6
+pktq_out = TXQ0.1 TXQ1.1
+pipeline_txrx_type = TXTX
+
+[LOADB]
+type = LOADB
+core = 3
+pktq_in = SWQ0 SWQ1
+pktq_out = SWQ3 SWQ4
+outport_offset = 136
+phyport_offset = 204
+n_vnf_threads = 1
+prv_que_handler = (0)
+
+[VACL]
+type = ACL
+core = 4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ5 SWQ6
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+
+[VCGNAPT]
+type = CGNAPT
+core = 3
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = TXQ0.1 TXQ1.1 SWQ0
+phyport_offset = 204
+n_flows = 1048576
+key_offset = 192;64
+key_size = 8
+hash_offset = 200;72
+timer_period = 100
+max_clients_per_ip = 65535
+max_port_per_client = 10
+public_ip_port_range = 98103214:(1, 65535)
+vnf_set = (3,4,5)
+pkt_type = ipv4
+cgnapt_meta_offset = 128
+prv_que_handler = (0,)
+
+[VFW]
+type = VFW
+core = s0c4
+pktq_in = SWQ3 SWQ4
+pktq_out = SWQ7 SWQ8;TXQ0.0 TXQ1.0
+n_rules = 10000
+n_flows = 1000000
+pkt_type = ipv6
+traffic_type = 6
+tcp_time_wait = 10
+
diff --git a/common/VIL/l2l3_stack/lib_arp.c b/common/VIL/l2l3_stack/lib_arp.c
index e2f755f2..b8976d3a 100644
--- a/common/VIL/l2l3_stack/lib_arp.c
+++ b/common/VIL/l2l3_stack/lib_arp.c
@@ -71,7 +71,7 @@ uint32_t nd_buffer = ARP_BUF_DEFAULT;
#define IN6ADDRSZ 16
#define MAX_PORTS 32
-static int my_inet_pton_ipv6(int af, const char *src, void *dst);
+int my_inet_pton_ipv6(int af, const char *src, void *dst);
static int inet_pton_ipv6(const char *src, unsigned char *dst);
static int inet_pton_ipv4(const char *src, unsigned char *dst);
static void local_arp_cache_init(void);
@@ -983,10 +983,13 @@ void remove_arp_entry(struct arp_entry_data *ret_arp_data, void *arg)
struct arp_timer_key *arp_key = (struct arp_timer_key *)arg;
lib_arp_delete_called++;
- rte_timer_stop(ret_arp_data->timer);
- rte_free(ret_arp_data->timer_key);
- rte_free(ret_arp_data->buf_pkts);
- ret_arp_data->buf_pkts = NULL;
+ if (ret_arp_data->timer) {
+ rte_timer_stop(ret_arp_data->timer);
+ rte_free(ret_arp_data->timer_key);
+ rte_free(ret_arp_data->buf_pkts);
+ ret_arp_data->buf_pkts = NULL;
+ }
+
if (ARPICMP_DEBUG) {
RTE_LOG(INFO, LIBARP,
"ARP Entry Deleted for IP :%d.%d.%d.%d , port %d\n",
@@ -1164,7 +1167,7 @@ populate_arp_entry(const struct ether_addr *hw_addr, uint32_t ipaddr,
if (new_arp_data->status == STALE) {
new_arp_data->status = PROBE;
if (ifm_chk_port_ipv4_enabled
- (new_arp_data->port)) {
+ (new_arp_data->port) != IFM_FAILURE) {
request_arp(new_arp_data->port,
new_arp_data->ip);
} else {
@@ -1894,7 +1897,7 @@ void process_arpicmp_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port)
* author:
* Paul Vixie, 1996.
*/
-static int my_inet_pton_ipv6(int af, const char *src, void *dst)
+int my_inet_pton_ipv6(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
@@ -2618,7 +2621,7 @@ void arp_timer_callback(struct rte_timer *timer, void *arg)
}
if (ifm_chk_port_ipv4_enabled
- (ret_arp_data->port)) {
+ (ret_arp_data->port) != IFM_FAILURE) {
request_arp(ret_arp_data->port,
ret_arp_data->ip);
} else {
diff --git a/common/VIL/l2l3_stack/lib_arp.h b/common/VIL/l2l3_stack/lib_arp.h
index 49b35f3d..c635c94c 100644
--- a/common/VIL/l2l3_stack/lib_arp.h
+++ b/common/VIL/l2l3_stack/lib_arp.h
@@ -58,6 +58,26 @@ extern void prefetch(void);
extern void update_nhip_access(uint8_t);
uint32_t get_arp_buf(void);
uint32_t get_nd_buf(void);
+extern int my_inet_pton_ipv6(int af, const char *src, void *dst);
+extern struct rte_hash *arp_hash_handle;
+extern struct rte_hash *nd_hash_handle;
+extern uint32_t lib_arp_get_mac_req;
+extern uint32_t lib_arp_nh_found;
+extern uint32_t lib_arp_no_nh_found;
+extern uint32_t lib_arp_arp_entry_found;
+extern uint32_t lib_arp_no_arp_entry_found;
+extern uint32_t lib_arp_populate_called;
+extern uint32_t lib_arp_delete_called;
+extern uint32_t lib_arp_duplicate_found;
+extern uint32_t arp_route_tbl_index;
+extern uint32_t lib_nd_get_mac_req;
+extern uint32_t lib_nd_nh_found;
+extern uint32_t lib_nd_no_nh_found;
+extern uint32_t lib_nd_nd_entry_found;
+extern uint32_t lib_nd_no_arp_entry_found;
+extern uint32_t lib_nd_populate_called;
+extern uint32_t lib_nd_delete_called;
+extern uint32_t lib_nd_duplicate_found;
enum {
ARP_FOUND,
diff --git a/common/VIL/l2l3_stack/tsx.h b/common/VIL/l2l3_stack/tsx.h
index 8b748165..01bde702 100644
--- a/common/VIL/l2l3_stack/tsx.h
+++ b/common/VIL/l2l3_stack/tsx.h
@@ -16,8 +16,14 @@
#ifndef _TSX_H_
#define _RSX_H_
#include <rte_atomic.h>
+
+#ifndef TRUE
#define TRUE 1
+#endif
+
+#ifndef FALSE
#define FALSE 0
+#endif
volatile int mutex_val;
diff --git a/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c
index 6b42ad77..607d13d1 100644
--- a/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c
+++ b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c
@@ -70,6 +70,14 @@ struct cmd_arp_add_result {
};
+uint16_t str2flowtype(char *string);
+int parse_flexbytes(const char *q_arg, uint8_t *flexbytes,
+ uint16_t max_num);
+enum rte_eth_input_set_field str2inset(char *string);
+int app_pipeline_arpicmp_entry_dbg(struct app_params *app,
+ uint32_t pipeline_id, uint8_t *msg);
+
+
static void
cmd_arp_add_parsed(void *parsed_result,
__rte_unused struct cmdline *cl, __rte_unused void *data)
@@ -952,8 +960,7 @@ cmdline_parse_inst_t cmd_set_fwd_mode = {
#if 1
-static uint16_t
-str2flowtype(char *string)
+uint16_t str2flowtype(char *string)
{
uint8_t i = 0;
static const struct {
@@ -983,7 +990,7 @@ str2flowtype(char *string)
return RTE_ETH_FLOW_UNKNOWN;
}
-static inline int
+int
parse_flexbytes(const char *q_arg, uint8_t *flexbytes, uint16_t max_num)
{
char s[256];
@@ -1442,7 +1449,7 @@ struct cmd_set_hash_input_set_result {
cmdline_fixed_string_t select;
};
-static enum rte_eth_input_set_field
+enum rte_eth_input_set_field
str2inset(char *string)
{
uint16_t i;
@@ -1966,7 +1973,7 @@ cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
};
#endif
-static int
+int
app_pipeline_arpicmp_entry_dbg(struct app_params *app,
uint32_t pipeline_id, uint8_t *msg)
{
diff --git a/common/VIL/pipeline_common/pipeline_common_fe.c b/common/VIL/pipeline_common/pipeline_common_fe.c
index 957f5df1..6fc6109c 100644
--- a/common/VIL/pipeline_common/pipeline_common_fe.c
+++ b/common/VIL/pipeline_common/pipeline_common_fe.c
@@ -35,6 +35,8 @@
#include "lib_arp.h"
#include "gateway.h"
+void app_run_file(cmdline_parse_ctx_t *ctx, const char *file_name);
+
int
app_pipeline_ping(struct app_params *app,
uint32_t pipeline_id)
@@ -1577,7 +1579,7 @@ static cmdline_parse_inst_t cmd_quit = {
* run
*/
-static void
+void
app_run_file(
cmdline_parse_ctx_t *ctx,
const char *file_name)
diff --git a/common/VIL/pipeline_master/pipeline_master_be.c b/common/VIL/pipeline_master/pipeline_master_be.c
index 425e2334..cc50497e 100644
--- a/common/VIL/pipeline_master/pipeline_master_be.c
+++ b/common/VIL/pipeline_master/pipeline_master_be.c
@@ -28,6 +28,8 @@
#include "app.h"
#include "pipeline_master_be.h"
+struct cmdline *pipe_cl;
+
struct pipeline_master {
struct app_params *app;
struct cmdline *cl;
@@ -59,6 +61,7 @@ pipeline_init(__rte_unused struct pipeline_params *params, void *arg)
rte_free(p);
return NULL;
}
+ pipe_cl = p->cl;
p->script_file_done = 0;
if (app->script_file == NULL)
@@ -85,6 +88,7 @@ static int
pipeline_run(void *pipeline)
{
struct pipeline_master *p = (struct pipeline_master *) pipeline;
+
int status;
if (p->script_file_done == 0) {
diff --git a/common/vnf_common/app.h b/common/vnf_common/app.h
index 51c40c97..752780d9 100644
--- a/common/vnf_common/app.h
+++ b/common/vnf_common/app.h
@@ -566,6 +566,17 @@ do { \
fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__); \
} while (0)
+#ifdef REST_API_SUPPORT
+static inline int rest_api_supported(void)
+{
+ return 1;
+}
+#else
+static inline int rest_api_supported(void)
+{
+ return 0;
+}
+#endif
static inline uint32_t
app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
{
@@ -955,6 +966,11 @@ int app_config_check(struct app_params *app);
int app_init(struct app_params *app);
+struct mg_context *rest_api_init(struct app_params *app);
+void set_vnf_type(const char *type);
+uint32_t is_rest_support(void);
+extern uint32_t rest_support;
+
int app_thread(void *arg);
int app_pipeline_type_register(struct app_params *app,
diff --git a/common/vnf_common/config_parse.c b/common/vnf_common/config_parse.c
index 5f7ec8a6..eeb547e6 100644
--- a/common/vnf_common/config_parse.c
+++ b/common/vnf_common/config_parse.c
@@ -35,6 +35,7 @@
/**
* Default config values
**/
+uint32_t rest_support = 1;
static struct app_params app_params_default = {
.config_file = "./config/ip_pipeline.cfg",
@@ -239,6 +240,11 @@ do { \
"Parse error in section \"%s\"", section_name); \
} while (0)
+uint32_t is_rest_support(void)
+{
+ return rest_support;
+}
+
int
parser_read_arg_bool(const char *p)
{
@@ -3264,6 +3270,9 @@ app_config_args(struct app_params *app, int argc, char **argv)
"more than once\n");
f_present = 1;
+ /* REST API not needed as user has supplied the config file */
+ rest_support = 0;
+
if (!strlen(optarg))
rte_panic("Error: Config file name is null\n");
@@ -3271,6 +3280,7 @@ app_config_args(struct app_params *app, int argc, char **argv)
if (app->config_file == NULL)
rte_panic("Error: Memory allocation failure\n");
+
break;
case 's':
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;
+}
diff --git a/tools/vnf_build.sh b/tools/vnf_build.sh
index 22a534ff..3b70166c 100755
--- a/tools/vnf_build.sh
+++ b/tools/vnf_build.sh
@@ -25,6 +25,7 @@ HUGEPGSZ=`cat /proc/meminfo | grep Hugepagesize | cut -d : -f 2 | tr -d ' '`
MODPROBE="/sbin/modprobe"
INSMOD="/sbin/insmod"
DPDK_DOWNLOAD="Not initialized"
+CIVETWEB_DOWNLOAD="Not initialized"
DPDK_DIR=$VNF_CORE/dpdk
DPDK_RTE_VER="17.02"
@@ -134,6 +135,8 @@ step_2()
FUNC[4]="install_dpdk"
TEXT[5]="Setup hugepages"
FUNC[5]="setup_hugepages"
+ TEXT[6]="Download civetweb"
+ FUNC[6]="download_civetweb_zip"
}
get_agreement_download()
{
@@ -176,7 +179,8 @@ install_libs()
sudo apt-get update
sudo apt-get -y install build-essential linux-headers-$(uname -r) git unzip libpcap0.8-dev gcc \
make libc6 libc6-dev g++-multilib libzmq3-dev libcurl4-openssl-dev net-tools wget gcc unzip \
- libpcap-dev libncurses-dev libedit-dev pciutils liblua5.2-dev libncursesw5-dev
+ libpcap-dev libncurses-dev libedit-dev pciutils liblua5.2-dev libncursesw5-dev libjson0 \
+ libjson0-dev libssl-dev
touch .download
}
@@ -197,6 +201,20 @@ download_dpdk_zip()
mv $VNF_CORE/dpdk-$DPDK_RTE_VER $VNF_CORE/dpdk
}
+download_civetweb_zip()
+{
+ echo "Download CIVETWEB zip"
+ CIVETWEB_DOWNLOAD="https://sourceforge.net/projects/civetweb/files/1.9/CivetWeb_V1.9.zip"
+ if [ ! -e ${CIVETWEB_DOWNLOAD##*/} ] ; then
+ wget ${CIVETWEB_DOWNLOAD}
+ fi
+ unzip -o ${CIVETWEB_DOWNLOAD##*/}
+ mv $VNF_CORE/civetweb-master $VNF_CORE/civetweb
+ pushd $VNF_CORE/civetweb
+ make lib
+ popd
+}
+
install_dpdk()
{
echo "Build DPDK"
@@ -220,7 +238,7 @@ install_dpdk()
patch -p1 < $VNF_CORE/patches/dpdk_custom_patch/set-log-level-to-info.patch
fi
- make -j install T=$RTE_TARGET
+ make -j16 install T=$RTE_TARGET
if [ $? -ne 0 ] ; then
echo "Failed to build dpdk, please check the errors."
return
@@ -309,6 +327,9 @@ non_interactive()
echo "Download dpdk for VNF build..."
download_dpdk_zip
+ echo "Download civetweb for VNF build..."
+ download_civetweb_zip
+
echo "Build dpdk..."
install_dpdk