@@ -60,6 +60,7 @@ SRCS-y += sp4.c
SRCS-y += sp6.c
SRCS-y += sa.c
SRCS-y += rt.c
+SRCS-y += eth.c
SRCS-y += ipsec-secgw.c
include $(RTE_SDK)/mk/rte.extapp.mk
@@ -158,3 +158,9 @@ rt ipv6 dst ffff:0000:0000:0000:5555:5555:0000:0000/116 port 2
rt ipv6 dst ffff:0000:0000:0000:6666:6666:0000:0000/116 port 3
rt ipv6 dst ffff:0000:1111:1111:0000:0000:0000:0000/116 port 2
rt ipv6 dst ffff:0000:1111:1111:1111:1111:0000:0000/116 port 3
+
+#ETH Addresses
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:7e:94:9a port 0
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:22:a1:d9 port 1
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:08:69:26 port 2
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:49:9e:dd port 3
@@ -158,3 +158,9 @@ rt ipv6 dst 0000:0000:0000:0000:5555:5555:0000:0000/116 port 2
rt ipv6 dst 0000:0000:0000:0000:6666:6666:0000:0000/116 port 3
rt ipv6 dst 0000:0000:1111:1111:0000:0000:0000:0000/116 port 2
rt ipv6 dst 0000:0000:1111:1111:1111:1111:0000:0000/116 port 3
+
+#ETH Addresses
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:7e:94:9a port 0
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:22:a1:d9 port 1
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:08:69:26 port 2
+eth addr src 00:00:00:00:00:00 dst 00:16:3e:49:9e:dd port 3
new file mode 100644
@@ -0,0 +1,238 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Ethernet Address
+ */
+#include <stdint.h>
+#include <sys/types.h>
+#include <rte_ether.h>
+#include <rte_errno.h>
+#include <rte_ethdev.h>
+
+#include "ipsec.h"
+#include "parser.h"
+
+#define ETH_DST_MAX_RULES 1024
+
+struct addr {
+ uint8_t port;
+ struct ether_addr src;
+ struct ether_addr dst;
+};
+
+struct addr eth_addr[ETH_DST_MAX_RULES];
+uint32_t nb_eth_addr;
+
+void
+parse_eth_tokens(char **tokens, uint32_t n_tokens,
+ struct parse_status *status)
+{
+ uint32_t ti;
+ uint32_t *n_addr = NULL;
+ struct addr *addr = NULL;
+
+ if (strcmp(tokens[0], "addr") == 0) {
+ n_addr = &nb_eth_addr;
+ addr = ð_addr[*n_addr];
+
+ APP_CHECK(*n_addr <= ETH_DST_MAX_RULES - 1, status,
+ "too many eth dst rules, abort insertion\n");
+ if (status->status < 0)
+ return;
+ } else {
+ APP_CHECK(0, status, "unrecognized input \"%s\"",
+ tokens[0]);
+ return;
+ }
+
+ for (ti = 1; ti < n_tokens; ti++) {
+ if (strcmp(tokens[ti], "src") == 0) {
+ INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+ if (status->status < 0)
+ return;
+
+ if (addr != NULL) {
+ APP_CHECK(parse_eth_addr(tokens[ti],
+ &addr->src) == 0, status,
+ "unrecognized input \"%s\", "
+ "expect valid src addr",
+ tokens[ti]);
+ if (status->status < 0)
+ return;
+ } else {
+ APP_CHECK(0, status, "addr is NULL");
+ }
+ }
+
+ if (strcmp(tokens[ti], "dst") == 0) {
+ INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+ if (status->status < 0)
+ return;
+
+ if (addr != NULL) {
+ APP_CHECK(parse_eth_addr(tokens[ti],
+ &addr->dst) == 0, status,
+ "unrecognized input \"%s\", "
+ "expect valid dst addr",
+ tokens[ti]);
+ if (status->status < 0)
+ return;
+ } else {
+ APP_CHECK(0, status, "addr is NULL");
+ }
+ }
+
+ if (strcmp(tokens[ti], "port") == 0) {
+ INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+ if (status->status < 0)
+ return;
+
+ APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
+ if (status->status < 0)
+ return;
+
+ if (addr != NULL)
+ addr->port = atoi(tokens[ti]);
+ else
+ APP_CHECK(0, status, "addr is NULL");
+ }
+ }
+
+ *n_addr = *n_addr + 1;
+}
+
+static struct eth_ctx *
+eth_create(const char *name, int32_t socket_id)
+{
+ char s[PATH_MAX];
+ struct eth_ctx *eth_ctx;
+ uint32_t mz_size;
+ const struct rte_memzone *mz;
+
+ snprintf(s, sizeof(s), "%s_%u", name, socket_id);
+
+ /* Create SA array table */
+ printf("Creating ETH context with %u maximum entries\n",
+ RTE_MAX_ETHPORTS);
+
+ mz_size = sizeof(struct eth_ctx) * RTE_MAX_ETHPORTS;
+ mz = rte_memzone_reserve(s, mz_size, socket_id,
+ RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
+ if (mz == NULL) {
+ printf("Failed to allocate SA DB memory\n");
+ rte_errno = -ENOMEM;
+ return NULL;
+ }
+ memset(mz->addr, 0, mz_size);
+
+ eth_ctx = (struct eth_ctx *)mz->addr;
+ return eth_ctx;
+}
+
+static void
+eth_ctx_dump(struct eth_ctx *eth_addr, uint32_t mask)
+{
+ char name[256];
+ uint32_t nb_ports;
+ uint8_t port;
+
+ nb_ports = rte_eth_dev_count();
+ for (port = 0; port < nb_ports; ++port) {
+ if ((mask & (1 << port)) == 0)
+ continue;
+
+ if (rte_eth_dev_get_name_by_port(port, name) < 0)
+ rte_exit(EXIT_FAILURE, "Unable to find name "
+ "to port=%d\n", port);
+
+ printf("%s-dst-0x%lx\n", name, eth_addr[port].dst);
+ printf("%s-src-0x%lx\n", name, eth_addr[port].src);
+ }
+}
+
+void
+eth_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t mask)
+{
+ const char *name;
+ uint32_t i, nb_ports;
+ uint8_t port;
+ struct ether_addr ethaddr;
+
+ if (ctx == NULL)
+ rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+ if (ctx->eth_addr != NULL)
+ rte_exit(EXIT_FAILURE, "ETH Address Table for socket %u "
+ "already initialized\n", socket_id);
+
+ if (nb_eth_addr == 0)
+ RTE_LOG(WARNING, IPSEC, "No ETH address rule specified\n");
+
+ /* create the ETH table */
+ name = "eth_addr";
+ ctx->eth_addr = eth_create(name, socket_id);
+ if (ctx->eth_addr == NULL)
+ rte_exit(EXIT_FAILURE, "Error [%d] creating ETH "
+ "context %s in socket %d\n", rte_errno,
+ name, socket_id);
+
+ /* populate the ETH table */
+ for (i = 0; i < nb_eth_addr; ++i) {
+ port = eth_addr[i].port;
+
+ if (ctx->eth_addr[port].dst != 0)
+ rte_exit(EXIT_FAILURE, "ETH destination address "
+ "for port %u already in use\n",
+ port);
+ if (ctx->eth_addr[port].src != 0)
+ rte_exit(EXIT_FAILURE, "ETH source address "
+ "for port %u already in use\n",
+ port);
+
+ ctx->eth_addr[port].dst = ETHADDR_TO_UINT64(eth_addr[i].dst);
+ ctx->eth_addr[port].src = ETHADDR_TO_UINT64(eth_addr[i].src);
+ }
+
+ nb_ports = rte_eth_dev_count();
+ for (port = 0; port < nb_ports; ++port) {
+ if ((mask & (1 << port)) == 0)
+ continue;
+
+ if (ctx->eth_addr[port].src == 0) {
+ rte_eth_macaddr_get(port, ðaddr);
+ ctx->eth_addr[port].src = ETHADDR_TO_UINT64(ethaddr);
+ }
+ }
+ eth_ctx_dump(ctx->eth_addr, mask);
+}
@@ -112,47 +112,6 @@
static uint16_t nb_rxd = IPSEC_SECGW_RX_DESC_DEFAULT;
static uint16_t nb_txd = IPSEC_SECGW_TX_DESC_DEFAULT;
-#if RTE_BYTE_ORDER != RTE_LITTLE_ENDIAN
-#define __BYTES_TO_UINT64(a, b, c, d, e, f, g, h) \
- (((uint64_t)((a) & 0xff) << 56) | \
- ((uint64_t)((b) & 0xff) << 48) | \
- ((uint64_t)((c) & 0xff) << 40) | \
- ((uint64_t)((d) & 0xff) << 32) | \
- ((uint64_t)((e) & 0xff) << 24) | \
- ((uint64_t)((f) & 0xff) << 16) | \
- ((uint64_t)((g) & 0xff) << 8) | \
- ((uint64_t)(h) & 0xff))
-#else
-#define __BYTES_TO_UINT64(a, b, c, d, e, f, g, h) \
- (((uint64_t)((h) & 0xff) << 56) | \
- ((uint64_t)((g) & 0xff) << 48) | \
- ((uint64_t)((f) & 0xff) << 40) | \
- ((uint64_t)((e) & 0xff) << 32) | \
- ((uint64_t)((d) & 0xff) << 24) | \
- ((uint64_t)((c) & 0xff) << 16) | \
- ((uint64_t)((b) & 0xff) << 8) | \
- ((uint64_t)(a) & 0xff))
-#endif
-#define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
-
-#define ETHADDR_TO_UINT64(addr) __BYTES_TO_UINT64( \
- addr.addr_bytes[0], addr.addr_bytes[1], \
- addr.addr_bytes[2], addr.addr_bytes[3], \
- addr.addr_bytes[4], addr.addr_bytes[5], \
- 0, 0)
-
-/* port/source ethernet addr and destination ethernet addr */
-struct ethaddr_info {
- uint64_t src, dst;
-};
-
-struct ethaddr_info ethaddr_tbl[RTE_MAX_ETHPORTS] = {
- { 0, ETHADDR(0x00, 0x16, 0x3e, 0x7e, 0x94, 0x9a) },
- { 0, ETHADDR(0x00, 0x16, 0x3e, 0x22, 0xa1, 0xd9) },
- { 0, ETHADDR(0x00, 0x16, 0x3e, 0x08, 0x69, 0x26) },
- { 0, ETHADDR(0x00, 0x16, 0x3e, 0x49, 0x9e, 0xdd) }
-};
-
/* mask of enabled ports */
static uint32_t enabled_port_mask;
static uint32_t unprotected_port_mask;
@@ -195,6 +154,7 @@ struct lcore_conf {
struct ipsec_ctx outbound;
struct rt_ctx *rt4_ctx;
struct rt_ctx *rt6_ctx;
+ struct eth_ctx *eth_addr;
} __rte_cache_aligned;
static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
@@ -290,7 +250,7 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
}
static inline void
-prepare_tx_pkt(struct rte_mbuf *pkt, uint16_t port)
+prepare_tx_pkt(struct rte_mbuf *pkt, uint64_t *src, uint64_t *dst)
{
struct ip *ip;
struct ether_hdr *ethhdr;
@@ -313,25 +273,24 @@ prepare_tx_pkt(struct rte_mbuf *pkt, uint16_t port)
ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
}
- memcpy(ðhdr->s_addr, ðaddr_tbl[port].src,
- sizeof(struct ether_addr));
- memcpy(ðhdr->d_addr, ðaddr_tbl[port].dst,
- sizeof(struct ether_addr));
+ memcpy(ðhdr->s_addr, src, sizeof(struct ether_addr));
+ memcpy(ðhdr->d_addr, dst, sizeof(struct ether_addr));
}
static inline void
-prepare_tx_burst(struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t port)
+prepare_tx_burst(struct rte_mbuf *pkts[], uint64_t *src, uint64_t *dst,
+ uint16_t nb_pkts)
{
int32_t i;
const int32_t prefetch_offset = 2;
for (i = 0; i < (nb_pkts - prefetch_offset); i++) {
rte_mbuf_prefetch_part2(pkts[i + prefetch_offset]);
- prepare_tx_pkt(pkts[i], port);
+ prepare_tx_pkt(pkts[i], src, dst);
}
/* Process left packets */
for (; i < nb_pkts; i++)
- prepare_tx_pkt(pkts[i], port);
+ prepare_tx_pkt(pkts[i], src, dst);
}
/* Send burst of packets on an output interface */
@@ -341,11 +300,14 @@ send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port)
struct rte_mbuf **m_table;
int32_t ret;
uint16_t queueid;
+ uint64_t *src, *dst;
queueid = qconf->tx_queue_id[port];
m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+ src = &qconf->eth_addr[port].src;
+ dst = &qconf->eth_addr[port].dst;
- prepare_tx_burst(m_table, n, port);
+ prepare_tx_burst(m_table, src, dst, n);
ret = rte_eth_tx_burst(port, queueid, m_table, n);
if (unlikely(ret < n)) {
@@ -707,6 +669,7 @@ main_loop(__attribute__((unused)) void *dummy)
qconf->rt4_ctx = socket_ctx[socket_id].rt_ip4;
qconf->rt6_ctx = socket_ctx[socket_id].rt_ip6;
+ qconf->eth_addr = socket_ctx[socket_id].eth_addr;
qconf->inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
@@ -1047,14 +1010,6 @@ parse_args(int32_t argc, char **argv)
return ret;
}
-static void
-print_ethaddr(const char *name, const struct ether_addr *eth_addr)
-{
- char buf[ETHER_ADDR_FMT_SIZE];
- ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
- printf("%s%s", name, buf);
-}
-
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
@@ -1341,17 +1296,11 @@ port_init(uint16_t portid)
uint16_t tx_queueid, rx_queueid, queue, lcore_id;
int32_t ret, socket_id;
struct lcore_conf *qconf;
- struct ether_addr ethaddr;
rte_eth_dev_info_get(portid, &dev_info);
printf("Configuring device port %u:\n", portid);
- rte_eth_macaddr_get(portid, ðaddr);
- ethaddr_tbl[portid].src = ETHADDR_TO_UINT64(ethaddr);
- print_ethaddr("Address: ", ðaddr);
- printf("\n");
-
nb_rx_queue = get_port_nb_rx_queues(portid);
nb_tx_queue = nb_lcores;
@@ -1502,6 +1451,8 @@ main(int32_t argc, char **argv)
rt_init(&socket_ctx[socket_id], socket_id);
+ eth_init(&socket_ctx[socket_id], socket_id, enabled_port_mask);
+
pool_init(&socket_ctx[socket_id], socket_id, NB_MBUF);
}
@@ -153,6 +153,10 @@ struct cdev_key {
uint8_t aead_algo;
};
+struct eth_ctx {
+ uint64_t src, dst;
+};
+
struct socket_ctx {
struct sa_ctx *sa_in;
struct sa_ctx *sa_out;
@@ -162,6 +166,7 @@ struct socket_ctx {
struct sp_ctx *sp_ip6_out;
struct rt_ctx *rt_ip4;
struct rt_ctx *rt_ip6;
+ struct eth_ctx *eth_addr;
struct rte_mempool *mbuf_pool;
struct rte_mempool *session_pool;
};
@@ -237,4 +242,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id);
void
rt_init(struct socket_ctx *ctx, int32_t socket_id);
+void
+eth_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t mask);
+
#endif /* __IPSEC_H__ */
@@ -292,6 +292,30 @@ parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)
}
int
+parse_eth_addr(const char *token, struct ether_addr *addr)
+{
+ char addr_str[256] = {0};
+ int i, values[6];
+
+ if (strlen(token) >= 256)
+ return -EINVAL;
+
+ strncpy(addr_str, token, strlen(token));
+
+ if (6 != sscanf(addr_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ &values[0], &values[1],
+ &values[2], &values[3],
+ &values[4], &values[5])) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 6; ++i)
+ addr->addr_bytes[i] = (uint8_t)values[i];
+
+ return 0;
+}
+
+int
parse_range(const char *token, uint16_t *low, uint16_t *high)
{
char ch;
@@ -469,11 +493,55 @@ cmdline_parse_inst_t cfg_rt_add_rule = {
},
};
+/* eth add parse */
+struct cfg_eth_add_cfg_item {
+ cmdline_fixed_string_t eth_keyword;
+ cmdline_multi_string_t multi_string;
+};
+
+static void
+cfg_eth_add_cfg_item_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl, void *data)
+{
+ struct cfg_eth_add_cfg_item *params = parsed_result;
+ char *tokens[32];
+ uint32_t n_tokens = RTE_DIM(tokens);
+ struct parse_status *status = (struct parse_status *)data;
+
+ APP_CHECK(parse_tokenize_string(
+ params->multi_string, tokens, &n_tokens) == 0,
+ status, "too many arguments\n");
+ if (status->status < 0)
+ return;
+
+ parse_eth_tokens(tokens, n_tokens, status);
+}
+
+static cmdline_parse_token_string_t cfg_eth_add_eth_str =
+ TOKEN_STRING_INITIALIZER(struct cfg_eth_add_cfg_item,
+ eth_keyword, "eth");
+
+static cmdline_parse_token_string_t cfg_eth_add_multi_str =
+ TOKEN_STRING_INITIALIZER(struct cfg_eth_add_cfg_item, multi_string,
+ TOKEN_STRING_MULTI);
+
+cmdline_parse_inst_t cfg_eth_add_rule = {
+ .f = cfg_eth_add_cfg_item_parsed,
+ .data = NULL,
+ .help_str = "",
+ .tokens = {
+ (void *) &cfg_eth_add_eth_str,
+ (void *) &cfg_eth_add_multi_str,
+ NULL,
+ },
+};
+
/** set of cfg items */
cmdline_parse_ctx_t ipsec_ctx[] = {
(cmdline_parse_inst_t *)&cfg_sp_add_rule,
(cmdline_parse_inst_t *)&cfg_sa_add_rule,
(cmdline_parse_inst_t *)&cfg_rt_add_rule,
+ (cmdline_parse_inst_t *)&cfg_eth_add_rule,
NULL,
};
@@ -499,6 +567,7 @@ parse_cfg_file(const char *cfg_filename)
cfg_sp_add_rule.data = &status;
cfg_sa_add_rule.data = &status;
cfg_rt_add_rule.data = &status;
+ cfg_eth_add_rule.data = &status;
do {
char oneline[1024];
@@ -85,6 +85,34 @@ do { \
index++; \
} while (0)
+#if RTE_BYTE_ORDER != RTE_LITTLE_ENDIAN
+#define __BYTES_TO_UINT64(a, b, c, d, e, f, g, h) \
+ (((uint64_t)((a) & 0xff) << 56) | \
+ ((uint64_t)((b) & 0xff) << 48) | \
+ ((uint64_t)((c) & 0xff) << 40) | \
+ ((uint64_t)((d) & 0xff) << 32) | \
+ ((uint64_t)((e) & 0xff) << 24) | \
+ ((uint64_t)((f) & 0xff) << 16) | \
+ ((uint64_t)((g) & 0xff) << 8) | \
+ ((uint64_t)(h) & 0xff))
+#else
+#define __BYTES_TO_UINT64(a, b, c, d, e, f, g, h) \
+ (((uint64_t)((h) & 0xff) << 56) | \
+ ((uint64_t)((g) & 0xff) << 48) | \
+ ((uint64_t)((f) & 0xff) << 40) | \
+ ((uint64_t)((e) & 0xff) << 32) | \
+ ((uint64_t)((d) & 0xff) << 24) | \
+ ((uint64_t)((c) & 0xff) << 16) | \
+ ((uint64_t)((b) & 0xff) << 8) | \
+ ((uint64_t)(a) & 0xff))
+#endif
+
+#define ETHADDR_TO_UINT64(addr) __BYTES_TO_UINT64( \
+ addr.addr_bytes[0], addr.addr_bytes[1], \
+ addr.addr_bytes[2], addr.addr_bytes[3], \
+ addr.addr_bytes[4], addr.addr_bytes[5], \
+ 0, 0)
+
int
parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask);
@@ -92,6 +120,9 @@ int
parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask);
int
+parse_eth_addr(const char *token, struct ether_addr *addr);
+
+int
parse_range(const char *token, uint16_t *low, uint16_t *high);
void
@@ -110,6 +141,10 @@ void
parse_rt_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status);
+void
+parse_eth_tokens(char **tokens, uint32_t n_tokens,
+ struct parse_status *status);
+
int
parse_cfg_file(const char *cfg_filename);