aboutsummaryrefslogtreecommitdiffstats
path: root/examples/udpfwd/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/udpfwd/parse.c')
-rw-r--r--examples/udpfwd/parse.c586
1 files changed, 586 insertions, 0 deletions
diff --git a/examples/udpfwd/parse.c b/examples/udpfwd/parse.c
new file mode 100644
index 0000000..979145c
--- /dev/null
+++ b/examples/udpfwd/parse.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2016 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 "netbe.h"
+#include "parse.h"
+
+#define DEF_LINE_NUM 0x400
+
+static const struct {
+ const char *name;
+ uint16_t op;
+} name2feop[] = {
+ { .name = "rx", .op = RXONLY,},
+ { .name = "tx", .op = TXONLY,},
+ { .name = "echo", .op = RXTX,},
+ { .name = "fwd", .op = FWD,},
+};
+
+static int
+parse_ipv4_val(__rte_unused const char *key, const char *val, void *prm)
+{
+ union parse_val *rv;
+
+ rv = prm;
+ if (inet_pton(AF_INET, val, &rv->in.addr4) != 1)
+ return -EINVAL;
+ rv->in.family = AF_INET;
+ return 0;
+}
+
+static int
+parse_ipv6_val(__rte_unused const char *key, const char *val, void *prm)
+{
+ union parse_val *rv;
+
+ rv = prm;
+ if (inet_pton(AF_INET6, val, &rv->in.addr6) != 1)
+ return -EINVAL;
+ rv->in.family = AF_INET6;
+ return 0;
+}
+
+static int
+parse_ip_val(__rte_unused const char *key, const char *val, void *prm)
+{
+ if (parse_ipv6_val(key, val, prm) != 0 &&
+ parse_ipv4_val(key, val, prm) != 0)
+ return -EINVAL;
+ return 0;
+}
+
+
+#define PARSE_UINT8x16(s, v, l) \
+do { \
+ char *end; \
+ unsigned long t; \
+ errno = 0; \
+ t = strtoul((s), &end, 16); \
+ if (errno != 0 || end[0] != (l) || t > UINT8_MAX) \
+ return -EINVAL; \
+ (s) = end + 1; \
+ (v) = t; \
+} while (0)
+
+static int
+parse_mac_val(__rte_unused const char *key, const char *val, void *prm)
+{
+ union parse_val *rv;
+ const char *s;
+
+ rv = prm;
+ s = val;
+
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[0], ':');
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[1], ':');
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[2], ':');
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[3], ':');
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[4], ':');
+ PARSE_UINT8x16(s, rv->mac.addr_bytes[5], 0);
+ return 0;
+}
+
+static int
+parse_feop_val(__rte_unused const char *key, const char *val, void *prm)
+{
+ uint32_t i;
+ union parse_val *rv;
+
+ rv = prm;
+ for (i = 0; i != RTE_DIM(name2feop); i++) {
+ if (strcmp(val, name2feop[i].name) == 0) {
+ rv->u64 = name2feop[i].op;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int
+parse_kvargs(const char *arg, const char *keys_man[], uint32_t nb_man,
+ const char *keys_opt[], uint32_t nb_opt,
+ const arg_handler_t hndl[], union parse_val val[])
+{
+ uint32_t j, k;
+ struct rte_kvargs *kvl;
+
+ kvl = rte_kvargs_parse(arg, NULL);
+ if (kvl == NULL) {
+ RTE_LOG(ERR, USER1,
+ "%s: invalid parameter: %s\n",
+ __func__, arg);
+ return -EINVAL;
+ }
+
+ for (j = 0; j != nb_man; j++) {
+ if (rte_kvargs_count(kvl, keys_man[j]) == 0) {
+ RTE_LOG(ERR, USER1,
+ "%s: %s missing mandatory key: %s\n",
+ __func__, arg, keys_man[j]);
+ rte_kvargs_free(kvl);
+ return -EINVAL;
+ }
+ }
+
+ for (j = 0; j != nb_man; j++) {
+ if (rte_kvargs_process(kvl, keys_man[j], hndl[j],
+ val + j) != 0) {
+ RTE_LOG(ERR, USER1,
+ "%s: %s invalid value for key: %s\n",
+ __func__, arg, keys_man[j]);
+ rte_kvargs_free(kvl);
+ return -EINVAL;
+ }
+ }
+
+ for (j = 0; j != nb_opt; j++) {
+ k = j + nb_man;
+ if (rte_kvargs_process(kvl, keys_opt[j], hndl[k],
+ val + k) != 0) {
+ RTE_LOG(ERR, USER1,
+ "%s: %s invalid value for key: %s\n",
+ __func__, arg, keys_opt[j]);
+ rte_kvargs_free(kvl);
+ return -EINVAL;
+ }
+ }
+
+ rte_kvargs_free(kvl);
+ return 0;
+}
+
+int
+parse_netbe_arg(struct netbe_port *prt, const char *arg)
+{
+ int32_t rc;
+
+ static const char *keys_man[] = {
+ "port",
+ "lcore",
+ };
+
+ static const char *keys_opt[] = {
+ "mtu",
+ "rx_offload",
+ "tx_offload",
+ "ipv4",
+ "ipv6",
+ };
+
+ static const arg_handler_t hndl[] = {
+ parse_uint_val,
+ parse_uint_val,
+ parse_uint_val,
+ parse_uint_val,
+ parse_uint_val,
+ parse_ipv4_val,
+ parse_ipv6_val,
+ };
+
+ union parse_val val[RTE_DIM(hndl)];
+
+ memset(val, 0, sizeof(val));
+ val[2].u64 = ETHER_MAX_VLAN_FRAME_LEN - ETHER_CRC_LEN;
+
+ rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
+ keys_opt, RTE_DIM(keys_opt), hndl, val);
+ if (rc != 0)
+ return rc;
+
+ prt->id = val[0].u64;
+ prt->lcore = val[1].u64;
+ prt->mtu = val[2].u64;
+ prt->rx_offload = val[3].u64;
+ prt->tx_offload = val[4].u64;
+ prt->ipv4 = val[5].in.addr4.s_addr;
+ prt->ipv6 = val[6].in.addr6;
+
+ return 0;
+}
+static int
+check_netbe_dest(const struct netbe_dest *dst)
+{
+ if (dst->port >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, USER1, "%s(line=%u) invalid port=%u",
+ __func__, dst->line, dst->port);
+ return -EINVAL;
+ } else if ((dst->family == AF_INET &&
+ dst->prfx > sizeof(struct in_addr) * CHAR_BIT) ||
+ (dst->family == AF_INET6 &&
+ dst->prfx > sizeof(struct in6_addr) * CHAR_BIT)) {
+ RTE_LOG(ERR, USER1, "%s(line=%u) invalid masklen=%u",
+ __func__, dst->line, dst->prfx);
+ return -EINVAL;
+ } else if (dst->mtu > ETHER_MAX_JUMBO_FRAME_LEN - ETHER_CRC_LEN) {
+ RTE_LOG(ERR, USER1, "%s(line=%u) invalid mtu=%u",
+ __func__, dst->line, dst->mtu);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+parse_netbe_dest(struct netbe_dest *dst, const char *arg)
+{
+ int32_t rc;
+
+ static const char *keys_man[] = {
+ "port",
+ "addr",
+ "masklen",
+ "mac",
+ };
+
+ static const char *keys_opt[] = {
+ "mtu",
+ };
+
+ static const arg_handler_t hndl[] = {
+ parse_uint_val,
+ parse_ip_val,
+ parse_uint_val,
+ parse_mac_val,
+ parse_uint_val,
+ };
+
+ union parse_val val[RTE_DIM(hndl)];
+
+ /* set default values. */
+ memset(val, 0, sizeof(val));
+ val[4].u64 = ETHER_MAX_JUMBO_FRAME_LEN - ETHER_CRC_LEN;
+
+ rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
+ keys_opt, RTE_DIM(keys_opt), hndl, val);
+ if (rc != 0)
+ return rc;
+
+ dst->port = val[0].u64;
+ dst->family = val[1].in.family;
+ if (val[1].in.family == AF_INET)
+ dst->ipv4 = val[1].in.addr4;
+ else
+ dst->ipv6 = val[1].in.addr6;
+ dst->prfx = val[2].u64;
+ memcpy(&dst->mac, &val[3].mac, sizeof(dst->mac));
+ dst->mtu = val[4].u64;
+
+ return 0;
+}
+
+int
+netbe_parse_dest(const char *fname, struct netbe_dest_prm *prm)
+{
+ uint32_t i, ln, n, num;
+ int32_t rc;
+ size_t sz;
+ char *s;
+ FILE *f;
+ struct netbe_dest *dp;
+ char line[LINE_MAX];
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ RTE_LOG(ERR, USER1, "%s failed to open file \"%s\"\n",
+ __func__, fname);
+ return -EINVAL;
+ }
+
+ n = 0;
+ num = 0;
+ dp = NULL;
+
+ for (ln = 0; fgets(line, sizeof(line), f) != NULL; ln++) {
+
+ /* skip spaces at the start. */
+ for (s = line; isspace(s[0]); s++)
+ ;
+
+ /* skip comment line. */
+ if (s[0] == '#' || s[0] == 0)
+ continue;
+
+ /* skip spaces at the end. */
+ for (i = strlen(s); i-- != 0 && isspace(s[i]); s[i] = 0)
+ ;
+
+ if (n == num) {
+ num += DEF_LINE_NUM;
+ sz = sizeof(dp[0]) * num;
+ dp = realloc(dp, sizeof(dp[0]) * num);
+ if (dp == NULL) {
+ RTE_LOG(ERR, USER1,
+ "%s(%s) allocation of %zu bytes "
+ "failed\n",
+ __func__, fname, sz);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+
+ dp[n].line = ln + 1;
+ if ((rc = parse_netbe_dest(dp + n, s)) != 0 ||
+ (rc = check_netbe_dest(dp + n)) != 0) {
+ RTE_LOG(ERR, USER1, "%s(%s) failed to parse line %u\n",
+ __func__, fname, dp[n].line);
+ break;
+ }
+ n++;
+ }
+
+ fclose(f);
+
+ if (rc != 0) {
+ free(dp);
+ dp = NULL;
+ n = 0;
+ }
+
+ prm->dest = dp;
+ prm->nb_dest = n;
+ return rc;
+}
+
+static void
+pv2saddr(struct sockaddr_storage *ss, const union parse_val *pva,
+ const union parse_val *pvp)
+{
+ ss->ss_family = pva->in.family;
+ if (pva->in.family == AF_INET) {
+ struct sockaddr_in *si = (struct sockaddr_in *)ss;
+ si->sin_addr = pva->in.addr4;
+ si->sin_port = rte_cpu_to_be_16((uint16_t)pvp->u64);
+ } else {
+ struct sockaddr_in6 *si = (struct sockaddr_in6 *)ss;
+ si->sin6_addr = pva->in.addr6;
+ si->sin6_port = rte_cpu_to_be_16((uint16_t)pvp->u64);
+ }
+}
+
+static int
+parse_netfe_arg(struct netfe_stream_prm *sp, const char *arg)
+{
+ int32_t rc;
+
+ static const char *keys_man[] = {
+ "lcore",
+ "op",
+ "laddr",
+ "lport",
+ "raddr",
+ "rport",
+ };
+
+ static const char *keys_opt[] = {
+ "txlen",
+ "fwladdr",
+ "fwlport",
+ "fwraddr",
+ "fwrport",
+ };
+
+ static const arg_handler_t hndl[] = {
+ parse_uint_val,
+ parse_feop_val,
+ parse_ip_val,
+ parse_uint_val,
+ parse_ip_val,
+ parse_uint_val,
+ parse_uint_val,
+ parse_ip_val,
+ parse_uint_val,
+ parse_ip_val,
+ parse_uint_val,
+ };
+
+ union parse_val val[RTE_DIM(hndl)];
+
+ memset(val, 0, sizeof(val));
+ rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
+ keys_opt, RTE_DIM(keys_opt), hndl, val);
+ if (rc != 0)
+ return rc;
+
+ sp->lcore = val[0].u64;
+ sp->op = val[1].u64;
+ pv2saddr(&sp->sprm.prm.local_addr, val + 2, val + 3);
+ pv2saddr(&sp->sprm.prm.remote_addr, val + 4, val + 5);
+ sp->txlen = val[6].u64;
+ pv2saddr(&sp->fprm.prm.local_addr, val + 7, val + 8);
+ pv2saddr(&sp->fprm.prm.remote_addr, val + 9, val + 10);
+
+ return 0;
+}
+
+static const char *
+format_feop(uint16_t op)
+{
+ uint32_t i;
+
+ for (i = 0; i != RTE_DIM(name2feop); i++) {
+ if (name2feop[i].op == op)
+ return name2feop[i].name;
+ }
+
+ return NULL;
+}
+
+static int
+is_addr_wc(const struct sockaddr_storage *sp)
+{
+ const struct sockaddr_in *i4;
+ const struct sockaddr_in6 *i6;
+
+ if (sp->ss_family == AF_INET) {
+ i4 = (const struct sockaddr_in *)sp;
+ return (i4->sin_addr.s_addr == INADDR_ANY);
+ } else if (sp->ss_family == AF_INET6) {
+ i6 = (const struct sockaddr_in6 *)sp;
+ return (memcmp(&i6->sin6_addr, &in6addr_any,
+ sizeof(i6->sin6_addr)) == 0);
+ }
+ return 0;
+}
+
+static int
+check_netfe_arg(const struct netfe_stream_prm *sp)
+{
+ char buf[INET6_ADDRSTRLEN];
+
+ if (sp->sprm.prm.local_addr.ss_family !=
+ sp->sprm.prm.remote_addr.ss_family) {
+ RTE_LOG(ERR, USER1, "invalid arg at line %u: "
+ "laddr and raddr for different protocols\n",
+ sp->line);
+ return -EINVAL;
+ }
+
+ if (sp->op == TXONLY) {
+ if (sp->txlen > RTE_MBUF_DEFAULT_DATAROOM || sp->txlen == 0) {
+ RTE_LOG(ERR, USER1, "invalid arg at line %u: txlen=%u "
+ "exceeds allowed values: (0, %u]\n",
+ sp->line, sp->txlen, RTE_MBUF_DEFAULT_DATAROOM);
+ return -EINVAL;
+ } else if (is_addr_wc(&sp->sprm.prm.remote_addr)) {
+ RTE_LOG(ERR, USER1, "invalid arg at line %u: "
+ "raddr=%s are not allowed for op=%s;\n",
+ sp->line,
+ format_addr(&sp->sprm.prm.remote_addr,
+ buf, sizeof(buf)),
+ format_feop(sp->op));
+ return -EINVAL;
+ }
+ } else if (sp->op == FWD) {
+ if (sp->fprm.prm.local_addr.ss_family !=
+ sp->fprm.prm.remote_addr.ss_family) {
+ RTE_LOG(ERR, USER1, "invalid arg at line %u: "
+ "fwladdr and fwraddr for different protocols\n",
+ sp->line);
+ return -EINVAL;
+ } else if (is_addr_wc(&sp->fprm.prm.remote_addr)) {
+ RTE_LOG(ERR, USER1, "invalid arg at line %u: "
+ "fwaddr=%s are not allowed for op=%s;\n",
+ sp->line,
+ format_addr(&sp->fprm.prm.remote_addr,
+ buf, sizeof(buf)),
+ format_feop(sp->op));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int
+netfe_parse_cfg(const char *fname, struct netfe_lcore_prm *lp)
+{
+ uint32_t i, ln, n, num;
+ int32_t rc;
+ size_t sz;
+ char *s;
+ FILE *f;
+ struct netfe_stream_prm *sp;
+ char line[LINE_MAX];
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ RTE_LOG(ERR, USER1, "%s failed to open file \"%s\"\n",
+ __func__, fname);
+ return -EINVAL;
+ }
+
+ n = 0;
+ num = 0;
+ sp = NULL;
+
+ for (ln = 0; fgets(line, sizeof(line), f) != NULL; ln++) {
+
+ /* skip spaces at the start. */
+ for (s = line; isspace(s[0]); s++)
+ ;
+
+ /* skip comment line. */
+ if (s[0] == '#' || s[0] == 0)
+ continue;
+
+ /* skip spaces at the end. */
+ for (i = strlen(s); i-- != 0 && isspace(s[i]); s[i] = 0)
+ ;
+
+ if (n == lp->max_streams) {
+ RTE_LOG(ERR, USER1,
+ "%s(%s) number of entries exceed max streams "
+ "value: %u\n",
+ __func__, fname, n);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (n == num) {
+ num += DEF_LINE_NUM;
+ sz = sizeof(sp[0]) * num;
+ sp = realloc(sp, sizeof(sp[0]) * num);
+ if (sp == NULL) {
+ RTE_LOG(ERR, USER1,
+ "%s(%s) allocation of %zu bytes "
+ "failed\n",
+ __func__, fname, sz);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+
+ sp[n].line = ln + 1;
+ if ((rc = parse_netfe_arg(sp + n, s)) != 0 ||
+ (rc = check_netfe_arg(sp + n)) != 0) {
+ RTE_LOG(ERR, USER1, "%s(%s) failed to parse line %u\n",
+ __func__, fname, sp[n].line);
+ break;
+ }
+ n++;
+ }
+
+ fclose(f);
+
+ if (rc != 0) {
+ free(sp);
+ sp = NULL;
+ n = 0;
+ }
+
+ lp->stream = sp;
+ lp->nb_streams = n;
+ return rc;
+}