summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/cfgfile.c
diff options
context:
space:
mode:
authorDeepak S <deepak.s@linux.intel.com>2017-07-13 21:26:50 -0700
committerDeepak S <deepak.s@linux.intel.com>2017-07-14 04:58:47 -0700
commit7286b2518ec8e4398b512ce95def9166a7af2e4a (patch)
treec93ef65d9e73e8893ccecb720152e16aae96a8b6 /VNFs/DPPD-PROX/cfgfile.c
parentadcb79da90176b27224eeb1d00aa0e611ef85a9b (diff)
Adding PROX(Packet pROcessing eXecution engine) VNF to sampleVNF
JIRA: SAMPLEVNF-55 PROX is a DPDK-based application implementing Telco use-cases such as a simplified BRAS/BNG, light-weight AFTR... It also allows configuring finer grained network functions like QoS, Routing, load-balancing... (We are moving PROX version v039 to sampleVNF https://01.org/intel-data-plane-performance-demonstrators/prox-overview) Change-Id: Ia3cb02cf0e49ac5596e922c197ff7e010293d033 Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'VNFs/DPPD-PROX/cfgfile.c')
-rw-r--r--VNFs/DPPD-PROX/cfgfile.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/cfgfile.c b/VNFs/DPPD-PROX/cfgfile.c
new file mode 100644
index 00000000..80a90937
--- /dev/null
+++ b/VNFs/DPPD-PROX/cfgfile.c
@@ -0,0 +1,339 @@
+/*
+// Copyright (c) 2010-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 "cfgfile.h"
+
+#include <rte_string_fns.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "parse_utils.h"
+#include "log.h"
+#include "quit.h"
+
+#define UINT32_MAX_STR "4294967295"
+
+/*
+ * Allocate cfg_file structure.
+ * Returns pointer to the allocated structure, NULL otherwise.
+ */
+struct cfg_file *cfg_open(const char *cfg_name)
+{
+ if (cfg_name == NULL) {
+ plog_err("\tNo config file name provided\n");
+ return NULL;
+ }
+ if (access(cfg_name, F_OK)) {
+ plog_err("\tError opening config file '%s': %s\n", cfg_name, strerror(errno));
+ return NULL;
+ }
+
+ FILE *pf = fopen(cfg_name, "rb");
+ if (pf == NULL) {
+ plog_err("\tError opening config file '%s'\n", cfg_name);
+ return NULL;
+ }
+
+ struct cfg_file *pcfg = calloc(1, sizeof(struct cfg_file));
+
+ if (pcfg == NULL) {
+ fclose(pf);
+ plog_err("\tCouldn't allocate memory for config file struct\n");
+ return NULL;
+ }
+
+ pcfg->pfile = pf;
+ pcfg->name = strdup(cfg_name);
+
+ return pcfg;
+}
+
+/* Free memory allocated for cfg_file structure.
+ * Returns 0 on success, -1 if the pointer to the pcfg is invalid */
+int cfg_close(struct cfg_file *pcfg)
+{
+ if (pcfg == NULL) {
+ return -1;
+ }
+
+ if (pcfg->name != NULL) {
+ free(pcfg->name);
+ }
+ if (pcfg->err_section != NULL) {
+ free(pcfg->err_section);
+ }
+ if (pcfg->pfile != NULL) {
+ fclose(pcfg->pfile);
+ }
+
+ free(pcfg);
+ return 0;
+}
+
+static int cfg_get_pos(struct cfg_file *pcfg, fpos_t *pos)
+{
+ pcfg->index_line = pcfg->line;
+ return fgetpos(pcfg->pfile, pos);
+}
+
+static int cfg_set_pos(struct cfg_file *pcfg, fpos_t *pos)
+{
+ pcfg->line = pcfg->index_line;
+ return fsetpos(pcfg->pfile, pos);
+}
+
+/*
+ * Read a line from the configuration file.
+ * Returns: on success length of the line read from the file is returned,
+ * 0 to indicate End of File,
+ * -1 in case of wrong function parameters
+ */
+static int cfg_get_line(struct cfg_file *pcfg, char *buffer, unsigned len, int raw_lines)
+{
+ char *ptr;
+
+ if (pcfg == NULL || pcfg->pfile == NULL || buffer == NULL || len == 0) {
+ return -1;
+ }
+
+ do {
+ ptr = fgets(buffer, len, pcfg->pfile);
+ if (ptr == NULL) {
+ return 0; /* end of file */
+ }
+ ++pcfg->line;
+
+ if (raw_lines) {
+ break;
+ }
+
+ /* remove comments */
+ ptr = strchr(buffer, ';');
+ if (ptr != NULL) {
+ *ptr = '\0';
+ }
+ else {
+ ptr = strchr(buffer, '\0');
+ }
+
+ /* remove trailing spaces */
+ if (ptr != buffer) {
+ ptr--;
+ while (isspace(*ptr)) {
+ *ptr = '\0';
+ ptr--;
+ }
+ }
+
+ ptr = buffer;
+ /* remove leading spaces */
+ while (*ptr && isspace(*ptr)) {
+ ++ptr;
+ }
+ if (ptr != buffer) {
+ strcpy(buffer, ptr);
+ ptr = buffer;
+ }
+ }
+ while (*ptr == '\0'); /* skip empty strings */
+
+ return strlen(buffer);
+}
+
+/*
+ * Checks if buffer contains section name specified by the cfg_section pointer.
+ * Returns NULL if section name does not match, cfg_section pointer otherwise
+ */
+static struct cfg_section *cfg_check_section(char *buffer, struct cfg_section *psec)
+{
+ char *pend;
+ unsigned len;
+ static const char *valid = "0123456789,hs- \t";
+
+ pend = strchr(buffer, ']');
+ if (pend == NULL) {
+ return NULL; /* ']' not found: invalid section name */
+ }
+
+ *pend = '\0';
+
+ /* check if section is indexed */
+ pend = strchr(psec->name, '#');
+ if (pend == NULL) {
+ return (strcmp(buffer, psec->name) == 0) ? psec : NULL;
+ }
+
+ /* get section index */
+ len = pend - psec->name;
+ if (strncmp(buffer, psec->name, len) != 0) {
+ return NULL;
+ }
+ pend = buffer + len;
+ if (*pend == '\0') {
+ return NULL;
+ }
+ /* only numeric characters are valid for section index
+ (currently, variables not checked!) */
+ if (pend[0] != '$') {
+ for (len = 0; pend[len] != '\0'; ++len) {
+ if (strchr(valid, pend[len]) == NULL) {
+ return NULL;
+ }
+ }
+ }
+
+ psec->nbindex = parse_list_set(psec->indexp, pend, MAX_INDEX);
+ PROX_PANIC(psec->nbindex == -1, "\t\tError in cfg_check_section('%s'): %s\n", buffer, get_parse_err());
+
+ for (int i = 0; i < psec->nbindex; ++i) {
+ psec->indexp[i] |= CFG_INDEXED;
+ }
+
+ return psec;
+}
+
+static char *cfg_get_section_name(struct cfg_section *psec)
+{
+ char *name;
+
+ if (!(psec->indexp[0] & CFG_INDEXED)) {
+ return strdup(psec->name);
+ }
+
+ name = malloc(strlen(psec->name) + strlen(UINT32_MAX_STR));
+ if (name != NULL) {
+ strcpy(name, psec->name);
+ char *pidx = strchr(name, '#');
+ if (pidx != NULL) {
+ sprintf(pidx, "%u", psec->indexp[0] & ~CFG_INDEXED);
+ }
+ }
+ return name;
+}
+
+/*
+ * Reads configuration file and parses section specified by psec pointer.
+ * Returns 0 on success, -1 otherwise
+ */
+int cfg_parse(struct cfg_file *pcfg, struct cfg_section *psec)
+{
+ int error;
+ unsigned entry = 0;
+ fpos_t pos;
+ int index_count = 0;
+ struct cfg_section *section = NULL;
+ char buffer[sizeof(pcfg->cur_line)] = {0};
+
+ if (pcfg == NULL || psec == NULL) {
+ return -1;
+ }
+
+ pcfg->line = 0;
+ fseek(pcfg->pfile, 0, SEEK_SET);
+
+ /* read configuration file and parse section specified by psec pointer */
+ while (1) {
+ if (psec->raw_lines) {
+ /* skip until section starts */
+ char *lines = pcfg->cur_line;
+ size_t max_len = sizeof(pcfg->cur_line);
+ char *ret;
+
+ do {
+ ret = fgets(lines, max_len, pcfg->pfile);
+ if (ret && *ret == '[') {
+ section = cfg_check_section(lines + 1, psec);
+ }
+ } while (!section && ret);
+
+ if (!ret)
+ return 0;
+
+ do {
+
+ ret = fgets(buffer, sizeof(buffer), pcfg->pfile);
+ if (ret && *ret != '[') {
+ size_t l = strlen(buffer);
+ strncpy(lines, buffer, max_len);
+ max_len -= l;
+ lines += l;
+ }
+ } while ((ret && *ret != '['));
+
+ if (section != NULL) {
+ error = section->parser(section->indexp[index_count], pcfg->cur_line, section->data);
+ if (error != 0) {
+ section->error = error;
+ /* log only the very first error */
+ if (!pcfg->err_section) {
+ pcfg->err_line = pcfg->line;
+ pcfg->err_entry = entry;
+ pcfg->err_section = cfg_get_section_name(section);
+ }
+ return 0;
+ }
+ ++entry;
+ }
+ return 0;
+ }
+
+ while (cfg_get_line(pcfg, buffer, MAX_CFG_STRING_LEN, psec->raw_lines) > 0) {
+ strncpy(pcfg->cur_line, buffer, sizeof(pcfg->cur_line));
+ if (*buffer == '[') {
+ if (index_count + 1 < psec->nbindex) {
+ // Need to loop - go back to recorded postion in file
+ cfg_set_pos(pcfg, &pos);
+ ++index_count;
+ continue;
+ }
+ else {
+ section = cfg_check_section(buffer + 1, psec);
+ entry = 0;
+ index_count = 0;
+ cfg_get_pos(pcfg, &pos);
+ continue;
+ }
+ }
+ /* call parser procedure for each line in the section */
+ if (section != NULL) {
+ error = section->parser(section->indexp[index_count], buffer, section->data);
+ if (error != 0) {
+ section->error = error;
+ /* log only the very first error */
+ if (!pcfg->err_section) {
+ pcfg->err_line = pcfg->line;
+ pcfg->err_entry = entry;
+ pcfg->err_section = cfg_get_section_name(section);
+ }
+ return 0;
+ }
+ ++entry;
+ }
+ }
+ if (index_count + 1 < psec->nbindex) {
+ // Last core config contained multiple cores - loop back
+ cfg_set_pos(pcfg, &pos);
+ ++index_count;
+ }
+ else {
+ break;
+ }
+ }
+ return 0;
+}