net/softnic: add command interface
authorJasvinder Singh <jasvinder.singh@intel.com>
Fri, 8 Jun 2018 12:41:46 +0000 (13:41 +0100)
committerCristian Dumitrescu <cristian.dumitrescu@intel.com>
Thu, 12 Jul 2018 11:52:17 +0000 (13:52 +0200)
Add interface for softnic cli commands.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
drivers/net/softnic/Makefile
drivers/net/softnic/meson.build
drivers/net/softnic/parser.c [new file with mode: 0644]
drivers/net/softnic/parser.h [new file with mode: 0644]
drivers/net/softnic/rte_eth_softnic_cli.c [new file with mode: 0644]
drivers/net/softnic/rte_eth_softnic_internals.h

index d002062..cb95414 100644 (file)
@@ -32,6 +32,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_tap.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_action.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_pipeline.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_thread.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_cli.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += parser.c
 
 #
 # Export include files
index 16604fc..8d3b4a0 100644 (file)
@@ -11,5 +11,7 @@ sources = files('rte_eth_softnic_tm.c',
        'rte_eth_softnic_tap.c',
        'rte_eth_softnic_action.c',
        'rte_eth_softnic_pipeline.c',
-       'rte_eth_softnic_thread.c')
+       'rte_eth_softnic_thread.c',
+       'rte_eth_softnic_cli.c',
+       'parser.c')
 deps += ['pipeline', 'port', 'table', 'sched']
diff --git a/drivers/net/softnic/parser.c b/drivers/net/softnic/parser.c
new file mode 100644 (file)
index 0000000..7087b87
--- /dev/null
@@ -0,0 +1,685 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Intel Corporation.
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ */
+
+/* For inet_pton4() and inet_pton6() functions:
+ *
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <rte_errno.h>
+
+#include "parser.h"
+
+static uint32_t
+get_hex_val(char c)
+{
+       switch (c) {
+       case '0': case '1': case '2': case '3': case '4': case '5':
+       case '6': case '7': case '8': case '9':
+               return c - '0';
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               return c - 'A' + 10;
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               return c - 'a' + 10;
+       default:
+               return 0;
+       }
+}
+
+int
+softnic_parser_read_arg_bool(const char *p)
+{
+       p = skip_white_spaces(p);
+       int result = -EINVAL;
+
+       if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+               ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+               p += 3;
+               result = 1;
+       }
+
+       if (((p[0] == 'o') && (p[1] == 'n')) ||
+               ((p[0] == 'O') && (p[1] == 'N'))) {
+               p += 2;
+               result = 1;
+       }
+
+       if (((p[0] == 'n') && (p[1] == 'o')) ||
+               ((p[0] == 'N') && (p[1] == 'O'))) {
+               p += 2;
+               result = 0;
+       }
+
+       if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+               ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+               p += 3;
+               result = 0;
+       }
+
+       p = skip_white_spaces(p);
+
+       if (p[0] != '\0')
+               return -EINVAL;
+
+       return result;
+}
+
+int
+softnic_parser_read_uint64(uint64_t *value, const char *p)
+{
+       char *next;
+       uint64_t val;
+
+       p = skip_white_spaces(p);
+       if (!isdigit(*p))
+               return -EINVAL;
+
+       val = strtoul(p, &next, 10);
+       if (p == next)
+               return -EINVAL;
+
+       p = next;
+       switch (*p) {
+       case 'T':
+               val *= 1024ULL;
+               /* fall through */
+       case 'G':
+               val *= 1024ULL;
+               /* fall through */
+       case 'M':
+               val *= 1024ULL;
+               /* fall through */
+       case 'k':
+       case 'K':
+               val *= 1024ULL;
+               p++;
+               break;
+       }
+
+       p = skip_white_spaces(p);
+       if (*p != '\0')
+               return -EINVAL;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+       char *next;
+       uint64_t val;
+
+       p = skip_white_spaces(p);
+
+       val = strtoul(p, &next, 16);
+       if (p == next)
+               return -EINVAL;
+
+       p = skip_white_spaces(next);
+       if (*p != '\0')
+               return -EINVAL;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint32(uint32_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT32_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint32_hex(uint32_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64_hex(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT32_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint16(uint16_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT16_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint16_hex(uint16_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64_hex(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT16_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint8(uint8_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT8_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = softnic_parser_read_uint64_hex(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT8_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+softnic_parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
+{
+       uint32_t i;
+
+       if (string == NULL ||
+               tokens == NULL ||
+               (*n_tokens < 1))
+               return -EINVAL;
+
+       for (i = 0; i < *n_tokens; i++) {
+               tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
+               if (tokens[i] == NULL)
+                       break;
+       }
+
+       if (i == *n_tokens &&
+               strtok_r(string, PARSE_DELIMITER, &string) != NULL)
+               return -E2BIG;
+
+       *n_tokens = i;
+       return 0;
+}
+
+int
+softnic_parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+       char *c;
+       uint32_t len, i;
+
+       /* Check input parameters */
+       if (src == NULL ||
+               dst == NULL ||
+               size == NULL ||
+               (*size == 0))
+               return -1;
+
+       len = strlen(src);
+       if (((len & 3) != 0) ||
+               (len > (*size) * 2))
+               return -1;
+       *size = len / 2;
+
+       for (c = src; *c != 0; c++) {
+               if ((((*c) >= '0') && ((*c) <= '9')) ||
+                       (((*c) >= 'A') && ((*c) <= 'F')) ||
+                       (((*c) >= 'a') && ((*c) <= 'f')))
+                       continue;
+
+               return -1;
+       }
+
+       /* Convert chars to bytes */
+       for (i = 0; i < *size; i++)
+               dst[i] = get_hex_val(src[2 * i]) * 16 +
+                       get_hex_val(src[2 * i + 1]);
+
+       return 0;
+}
+
+int
+softnic_parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels)
+{
+       uint32_t n_max_labels = *n_labels, count = 0;
+
+       /* Check for void list of labels */
+       if (strcmp(string, "<void>") == 0) {
+               *n_labels = 0;
+               return 0;
+       }
+
+       /* At least one label should be present */
+       for ( ; (*string != '\0'); ) {
+               char *next;
+               int value;
+
+               if (count >= n_max_labels)
+                       return -1;
+
+               if (count > 0) {
+                       if (string[0] != ':')
+                               return -1;
+
+                       string++;
+               }
+
+               value = strtol(string, &next, 10);
+               if (next == string)
+                       return -1;
+               string = next;
+
+               labels[count++] = (uint32_t)value;
+       }
+
+       *n_labels = count;
+       return 0;
+}
+
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+
+/* int
+ * inet_pton4(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_pton4(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;
+
+               pch = strchr(digits, ch);
+               if (pch != 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_pton6(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_pton6(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 int dbloct_count = 0;
+
+       memset((tp = tmp), '\0', IN6ADDRSZ);
+       endp = tp + IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return 0;
+       curtok = src;
+       saw_xdigit = count_xdigit = 0;
+       val = 0;
+
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr((xdigits = xdigits_l), ch);
+               if (pch == 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_pton4(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 we already have 8 double octets, having a colon means error */
+               if (dbloct_count == 8)
+                       return 0;
+
+               /* Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               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 struct ether_addr *
+my_ether_aton(const char *a)
+{
+       int i;
+       char *end;
+       unsigned long o[ETHER_ADDR_LEN];
+       static struct ether_addr ether_addr;
+
+       i = 0;
+       do {
+               errno = 0;
+               o[i] = strtoul(a, &end, 16);
+               if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
+                       return NULL;
+               a = end + 1;
+       } while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0);
+
+       /* Junk at the end of line */
+       if (end[0] != 0)
+               return NULL;
+
+       /* Support the format XX:XX:XX:XX:XX:XX */
+       if (i == ETHER_ADDR_LEN) {
+               while (i-- != 0) {
+                       if (o[i] > UINT8_MAX)
+                               return NULL;
+                       ether_addr.addr_bytes[i] = (uint8_t)o[i];
+               }
+       /* Support the format XXXX:XXXX:XXXX */
+       } else if (i == ETHER_ADDR_LEN / 2) {
+               while (i-- != 0) {
+                       if (o[i] > UINT16_MAX)
+                               return NULL;
+                       ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
+                       ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
+               }
+       /* unknown format */
+       } else
+               return NULL;
+
+       return (struct ether_addr *)&ether_addr;
+}
+
+int
+softnic_parse_ipv4_addr(const char *token, struct in_addr *ipv4)
+{
+       if (strlen(token) >= INET_ADDRSTRLEN)
+               return -EINVAL;
+
+       if (inet_pton4(token, (unsigned char *)ipv4) != 1)
+               return -EINVAL;
+
+       return 0;
+}
+
+int
+softnic_parse_ipv6_addr(const char *token, struct in6_addr *ipv6)
+{
+       if (strlen(token) >= INET6_ADDRSTRLEN)
+               return -EINVAL;
+
+       if (inet_pton6(token, (unsigned char *)ipv6) != 1)
+               return -EINVAL;
+
+       return 0;
+}
+
+int
+softnic_parse_mac_addr(const char *token, struct ether_addr *addr)
+{
+       struct ether_addr *tmp;
+
+       tmp = my_ether_aton(token);
+       if (tmp == NULL)
+               return -1;
+
+       memcpy(addr, tmp, sizeof(struct ether_addr));
+       return 0;
+}
+
+int
+softnic_parse_cpu_core(const char *entry,
+       struct softnic_cpu_core_params *p)
+{
+       size_t num_len;
+       char num[8];
+
+       uint32_t s = 0, c = 0, h = 0, val;
+       uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+       const char *next = skip_white_spaces(entry);
+       char type;
+
+       if (p == NULL)
+               return -EINVAL;
+
+       /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+       while (*next != '\0') {
+               /* If everything parsed nothing should left */
+               if (s_parsed && c_parsed && h_parsed)
+                       return -EINVAL;
+
+               type = *next;
+               switch (type) {
+               case 's':
+               case 'S':
+                       if (s_parsed || c_parsed || h_parsed)
+                               return -EINVAL;
+                       s_parsed = 1;
+                       next++;
+                       break;
+               case 'c':
+               case 'C':
+                       if (c_parsed || h_parsed)
+                               return -EINVAL;
+                       c_parsed = 1;
+                       next++;
+                       break;
+               case 'h':
+               case 'H':
+                       if (h_parsed)
+                               return -EINVAL;
+                       h_parsed = 1;
+                       next++;
+                       break;
+               default:
+                       /* If it start from digit it must be only core id. */
+                       if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+                               return -EINVAL;
+
+                       type = 'C';
+               }
+
+               for (num_len = 0; *next != '\0'; next++, num_len++) {
+                       if (num_len == RTE_DIM(num))
+                               return -EINVAL;
+
+                       if (!isdigit(*next))
+                               break;
+
+                       num[num_len] = *next;
+               }
+
+               if (num_len == 0 && type != 'h' && type != 'H')
+                       return -EINVAL;
+
+               if (num_len != 0 && (type == 'h' || type == 'H'))
+                       return -EINVAL;
+
+               num[num_len] = '\0';
+               val = strtol(num, NULL, 10);
+
+               h = 0;
+               switch (type) {
+               case 's':
+               case 'S':
+                       s = val;
+                       break;
+               case 'c':
+               case 'C':
+                       c = val;
+                       break;
+               case 'h':
+               case 'H':
+                       h = 1;
+                       break;
+               }
+       }
+
+       p->socket_id = s;
+       p->core_id = c;
+       p->thread_id = h;
+       return 0;
+}
diff --git a/drivers/net/softnic/parser.h b/drivers/net/softnic/parser.h
new file mode 100644 (file)
index 0000000..5ab4763
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation
+ */
+
+#ifndef __INCLUDE_SOFTNIC_PARSER_H__
+#define __INCLUDE_SOFTNIC_PARSER_H__
+
+#include <stdint.h>
+
+#include <rte_ip.h>
+#include <rte_ether.h>
+
+#define PARSE_DELIMITER                                " \f\n\r\t\v"
+
+#define skip_white_spaces(pos)                 \
+({                                             \
+       __typeof__(pos) _p = (pos);             \
+       for ( ; isspace(*_p); _p++)             \
+               ;                               \
+       _p;                                     \
+})
+
+static inline size_t
+skip_digits(const char *src)
+{
+       size_t i;
+
+       for (i = 0; isdigit(src[i]); i++)
+               ;
+
+       return i;
+}
+
+int softnic_parser_read_arg_bool(const char *p);
+
+int softnic_parser_read_uint64(uint64_t *value, const char *p);
+int softnic_parser_read_uint32(uint32_t *value, const char *p);
+int softnic_parser_read_uint16(uint16_t *value, const char *p);
+int softnic_parser_read_uint8(uint8_t *value, const char *p);
+
+int softnic_parser_read_uint64_hex(uint64_t *value, const char *p);
+int softnic_parser_read_uint32_hex(uint32_t *value, const char *p);
+int softnic_parser_read_uint16_hex(uint16_t *value, const char *p);
+int softnic_parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int softnic_parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
+int softnic_parse_ipv4_addr(const char *token, struct in_addr *ipv4);
+int softnic_parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
+int softnic_parse_mac_addr(const char *token, struct ether_addr *addr);
+int softnic_parse_mpls_labels(char *string,
+               uint32_t *labels, uint32_t *n_labels);
+
+struct softnic_cpu_core_params {
+       uint32_t socket_id;
+       uint32_t core_id;
+       uint32_t thread_id;
+};
+
+int softnic_parse_cpu_core(const char *entry,
+               struct softnic_cpu_core_params *p);
+
+int softnic_parse_tokenize_string(char *string,
+               char *tokens[], uint32_t *n_tokens);
+
+#endif
diff --git a/drivers/net/softnic/rte_eth_softnic_cli.c b/drivers/net/softnic/rte_eth_softnic_cli.c
new file mode 100644 (file)
index 0000000..6d539a5
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rte_eth_softnic_internals.h"
+#include "parser.h"
+
+#ifndef CMD_MAX_TOKENS
+#define CMD_MAX_TOKENS     256
+#endif
+
+#define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
+#define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
+#define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
+
+static int
+is_comment(char *in)
+{
+       if ((strlen(in) && index("!#%;", in[0])) ||
+               (strncmp(in, "//", 2) == 0) ||
+               (strncmp(in, "--", 2) == 0))
+               return 1;
+
+       return 0;
+}
+
+void
+softnic_cli_process(char *in, char *out, size_t out_size, void *arg __rte_unused)
+{
+       char *tokens[CMD_MAX_TOKENS];
+       uint32_t n_tokens = RTE_DIM(tokens);
+       int status;
+
+       if (is_comment(in))
+               return;
+
+       status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
+       if (status) {
+               snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
+               return;
+       }
+
+       if (n_tokens == 0)
+               return;
+
+       snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
+}
+
+int
+softnic_cli_script_process(struct pmd_internals *softnic,
+       const char *file_name,
+       size_t msg_in_len_max,
+       size_t msg_out_len_max)
+{
+       char *msg_in = NULL, *msg_out = NULL;
+       FILE *f = NULL;
+
+       /* Check input arguments */
+       if (file_name == NULL ||
+               strlen(file_name) == 0 ||
+               msg_in_len_max == 0 ||
+               msg_out_len_max == 0)
+               return -EINVAL;
+
+       msg_in = malloc(msg_in_len_max + 1);
+       msg_out = malloc(msg_out_len_max + 1);
+       if (msg_in == NULL ||
+               msg_out == NULL) {
+               free(msg_out);
+               free(msg_in);
+               return -ENOMEM;
+       }
+
+       /* Open input file */
+       f = fopen(file_name, "r");
+       if (f == NULL) {
+               free(msg_out);
+               free(msg_in);
+               return -EIO;
+       }
+
+       /* Read file */
+       for ( ; ; ) {
+               if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
+                       break;
+
+               printf("%s", msg_in);
+               msg_out[0] = 0;
+
+               softnic_cli_process(msg_in,
+                       msg_out,
+                       msg_out_len_max,
+                       softnic);
+
+               if (strlen(msg_out))
+                       printf("%s", msg_out);
+       }
+
+       /* Close file */
+       fclose(f);
+       free(msg_out);
+       free(msg_in);
+       return 0;
+}
index 1c78942..d459571 100644 (file)
@@ -695,4 +695,19 @@ softnic_thread_init(struct pmd_internals *p);
 void
 softnic_thread_free(struct pmd_internals *p);
 
+/**
+ * CLI
+ */
+void
+softnic_cli_process(char *in,
+       char *out,
+       size_t out_size,
+       void *arg);
+
+int
+softnic_cli_script_process(struct pmd_internals *softnic,
+       const char *file_name,
+       size_t msg_in_len_max,
+       size_t msg_out_len_max);
+
 #endif /* __INCLUDE_RTE_ETH_SOFTNIC_INTERNALS_H__ */