#
# Compile SOFTNIC PMD
#
-CONFIG_RTE_LIBRTE_PMD_SOFTNIC=y
+CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n
#
# Compile the TAP PMD
CONFIG_RTE_LIBRTE_PMD_VHOST=y
CONFIG_RTE_LIBRTE_IFC_PMD=y
CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
+CONFIG_RTE_LIBRTE_PMD_SOFTNIC=y
CONFIG_RTE_LIBRTE_PMD_TAP=y
CONFIG_RTE_LIBRTE_AVP_PMD=y
CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=y
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
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += conn.c
#
# Export include files
#
SYMLINK-y-include += rte_eth_softnic.h
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(info Softnic PMD can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+all:
+clean:
+else
+
include $(RTE_SDK)/mk/rte.lib.mk
+
+endif
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#define __USE_GNU
+#include <sys/socket.h>
+
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "conn.h"
+
+#define MSG_CMD_TOO_LONG "Command too long."
+
+struct softnic_conn {
+ char *welcome;
+ char *prompt;
+ char *buf;
+ char *msg_in;
+ char *msg_out;
+ size_t buf_size;
+ size_t msg_in_len_max;
+ size_t msg_out_len_max;
+ size_t msg_in_len;
+ int fd_server;
+ int fd_client_group;
+ softnic_conn_msg_handle_t msg_handle;
+ void *msg_handle_arg;
+};
+
+struct softnic_conn *
+softnic_conn_init(struct softnic_conn_params *p)
+{
+ struct sockaddr_in server_address;
+ struct softnic_conn *conn;
+ int fd_server, fd_client_group, status;
+
+ memset(&server_address, 0, sizeof(server_address));
+
+ /* Check input arguments */
+ if (p == NULL ||
+ p->welcome == NULL ||
+ p->prompt == NULL ||
+ p->addr == NULL ||
+ p->buf_size == 0 ||
+ p->msg_in_len_max == 0 ||
+ p->msg_out_len_max == 0 ||
+ p->msg_handle == NULL)
+ return NULL;
+
+ status = inet_aton(p->addr, &server_address.sin_addr);
+ if (status == 0)
+ return NULL;
+
+ /* Memory allocation */
+ conn = calloc(1, sizeof(struct softnic_conn));
+ if (conn == NULL)
+ return NULL;
+
+ conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
+ conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
+ conn->buf = calloc(1, p->buf_size);
+ conn->msg_in = calloc(1, p->msg_in_len_max + 1);
+ conn->msg_out = calloc(1, p->msg_out_len_max + 1);
+
+ if (conn->welcome == NULL ||
+ conn->prompt == NULL ||
+ conn->buf == NULL ||
+ conn->msg_in == NULL ||
+ conn->msg_out == NULL) {
+ softnic_conn_free(conn);
+ return NULL;
+ }
+
+ /* Server socket */
+ server_address.sin_family = AF_INET;
+ server_address.sin_port = htons(p->port);
+
+ fd_server = socket(AF_INET,
+ SOCK_STREAM | SOCK_NONBLOCK,
+ 0);
+ if (fd_server == -1) {
+ softnic_conn_free(conn);
+ return NULL;
+ }
+
+ status = bind(fd_server,
+ (struct sockaddr *)&server_address,
+ sizeof(server_address));
+ if (status == -1) {
+ softnic_conn_free(conn);
+ close(fd_server);
+ return NULL;
+ }
+
+ status = listen(fd_server, 16);
+ if (status == -1) {
+ softnic_conn_free(conn);
+ close(fd_server);
+ return NULL;
+ }
+
+ /* Client group */
+ fd_client_group = epoll_create(1);
+ if (fd_client_group == -1) {
+ softnic_conn_free(conn);
+ close(fd_server);
+ return NULL;
+ }
+
+ /* Fill in */
+ strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
+ strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
+ conn->buf_size = p->buf_size;
+ conn->msg_in_len_max = p->msg_in_len_max;
+ conn->msg_out_len_max = p->msg_out_len_max;
+ conn->msg_in_len = 0;
+ conn->fd_server = fd_server;
+ conn->fd_client_group = fd_client_group;
+ conn->msg_handle = p->msg_handle;
+ conn->msg_handle_arg = p->msg_handle_arg;
+
+ return conn;
+}
+
+void
+softnic_conn_free(struct softnic_conn *conn)
+{
+ if (conn == NULL)
+ return;
+
+ if (conn->fd_client_group)
+ close(conn->fd_client_group);
+
+ if (conn->fd_server)
+ close(conn->fd_server);
+
+ free(conn->msg_out);
+ free(conn->msg_in);
+ free(conn->prompt);
+ free(conn->welcome);
+ free(conn);
+}
+
+int
+softnic_conn_poll_for_conn(struct softnic_conn *conn)
+{
+ struct sockaddr_in client_address;
+ struct epoll_event event;
+ socklen_t client_address_length;
+ int fd_client, status;
+
+ /* Check input arguments */
+ if (conn == NULL)
+ return -1;
+
+ /* Server socket */
+ client_address_length = sizeof(client_address);
+ fd_client = accept4(conn->fd_server,
+ (struct sockaddr *)&client_address,
+ &client_address_length,
+ SOCK_NONBLOCK);
+ if (fd_client == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return 0;
+
+ return -1;
+ }
+
+ /* Client group */
+ event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
+ event.data.fd = fd_client;
+
+ status = epoll_ctl(conn->fd_client_group,
+ EPOLL_CTL_ADD,
+ fd_client,
+ &event);
+ if (status == -1) {
+ close(fd_client);
+ return -1;
+ }
+
+ /* Client */
+ status = write(fd_client,
+ conn->welcome,
+ strlen(conn->welcome));
+ if (status == -1) {
+ close(fd_client);
+ return -1;
+ }
+
+ status = write(fd_client,
+ conn->prompt,
+ strlen(conn->prompt));
+ if (status == -1) {
+ close(fd_client);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+data_event_handle(struct softnic_conn *conn,
+ int fd_client)
+{
+ ssize_t len, i, status;
+
+ /* Read input message */
+
+ len = read(fd_client,
+ conn->buf,
+ conn->buf_size);
+ if (len == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return 0;
+
+ return -1;
+ }
+ if (len == 0)
+ return 0;
+
+ /* Handle input messages */
+ for (i = 0; i < len; i++) {
+ if (conn->buf[i] == '\n') {
+ size_t n;
+
+ conn->msg_in[conn->msg_in_len] = 0;
+ conn->msg_out[0] = 0;
+
+ conn->msg_handle(conn->msg_in,
+ conn->msg_out,
+ conn->msg_out_len_max,
+ conn->msg_handle_arg);
+
+ n = strlen(conn->msg_out);
+ if (n) {
+ status = write(fd_client,
+ conn->msg_out,
+ n);
+ if (status == -1)
+ return status;
+ }
+
+ conn->msg_in_len = 0;
+ } else if (conn->msg_in_len < conn->msg_in_len_max) {
+ conn->msg_in[conn->msg_in_len] = conn->buf[i];
+ conn->msg_in_len++;
+ } else {
+ status = write(fd_client,
+ MSG_CMD_TOO_LONG,
+ strlen(MSG_CMD_TOO_LONG));
+ if (status == -1)
+ return status;
+
+ conn->msg_in_len = 0;
+ }
+ }
+
+ /* Write prompt */
+ status = write(fd_client,
+ conn->prompt,
+ strlen(conn->prompt));
+ if (status == -1)
+ return status;
+
+ return 0;
+}
+
+static int
+control_event_handle(struct softnic_conn *conn,
+ int fd_client)
+{
+ int status;
+
+ status = epoll_ctl(conn->fd_client_group,
+ EPOLL_CTL_DEL,
+ fd_client,
+ NULL);
+ if (status == -1)
+ return -1;
+
+ status = close(fd_client);
+ if (status == -1)
+ return -1;
+
+ return 0;
+}
+
+int
+softnic_conn_poll_for_msg(struct softnic_conn *conn)
+{
+ struct epoll_event event;
+ int fd_client, status, status_data = 0, status_control = 0;
+
+ /* Check input arguments */
+ if (conn == NULL)
+ return -1;
+
+ /* Client group */
+ status = epoll_wait(conn->fd_client_group,
+ &event,
+ 1,
+ 0);
+ if (status == -1)
+ return -1;
+ if (status == 0)
+ return 0;
+
+ fd_client = event.data.fd;
+
+ /* Data available */
+ if (event.events & EPOLLIN)
+ status_data = data_event_handle(conn, fd_client);
+
+ /* Control events */
+ if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
+ status_control = control_event_handle(conn, fd_client);
+
+ if (status_data || status_control)
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct softnic_conn;
+
+#ifndef CONN_WELCOME_LEN_MAX
+#define CONN_WELCOME_LEN_MAX 1024
+#endif
+
+#ifndef CONN_PROMPT_LEN_MAX
+#define CONN_PROMPT_LEN_MAX 16
+#endif
+
+typedef void (*softnic_conn_msg_handle_t)(char *msg_in,
+ char *msg_out,
+ size_t msg_out_len_max,
+ void *arg);
+
+struct softnic_conn_params {
+ const char *welcome;
+ const char *prompt;
+ const char *addr;
+ uint16_t port;
+ size_t buf_size;
+ size_t msg_in_len_max;
+ size_t msg_out_len_max;
+ softnic_conn_msg_handle_t msg_handle;
+ void *msg_handle_arg;
+};
+
+struct softnic_conn *
+softnic_conn_init(struct softnic_conn_params *p);
+
+void
+softnic_conn_free(struct softnic_conn *conn);
+
+int
+softnic_conn_poll_for_conn(struct softnic_conn *conn);
+
+int
+softnic_conn_poll_for_msg(struct softnic_conn *conn);
+
+#endif
'rte_eth_softnic_pipeline.c',
'rte_eth_softnic_thread.c',
'rte_eth_softnic_cli.c',
- 'parser.c')
+ 'parser.c',
+ 'conn.c')
deps += ['pipeline', 'port', 'table', 'sched']
#include "rte_eth_softnic_internals.h"
#define PMD_PARAM_FIRMWARE "firmware"
-#define PMD_PARAM_CPU_ID "cpu_id"
-#define PMD_PARAM_SCRIPT "script"
#define PMD_PARAM_CONN_PORT "conn_port"
#define PMD_PARAM_CPU_ID "cpu_id"
#define PMD_PARAM_TM_N_QUEUES "tm_n_queues"
static const char *pmd_valid_args[] = {
PMD_PARAM_FIRMWARE,
+ PMD_PARAM_CONN_PORT,
PMD_PARAM_CPU_ID,
PMD_PARAM_TM_N_QUEUES,
PMD_PARAM_TM_QSIZE0,
NULL
};
+static const char welcome[] =
+ "\n"
+ "Welcome to Soft NIC!\n"
+ "\n";
+
+static const char prompt[] = "softnic> ";
+
+struct softnic_conn_params conn_params_default = {
+ .welcome = welcome,
+ .prompt = prompt,
+ .addr = "0.0.0.0",
+ .port = 0,
+ .buf_size = 1024 * 1024,
+ .msg_in_len_max = 1024,
+ .msg_out_len_max = 1024 * 1024,
+ .msg_handle = softnic_cli_process,
+ .msg_handle_arg = NULL,
+};
+
static const struct rte_eth_dev_info pmd_dev_info = {
.min_rx_bufsize = 0,
.max_rx_pktlen = UINT32_MAX,
return NULL;
}
+ if (params->conn_port) {
+ struct softnic_conn_params conn_params;
+
+ memcpy(&conn_params, &conn_params_default, sizeof(conn_params));
+ conn_params.port = p->params.conn_port;
+ conn_params.msg_handle_arg = p;
+
+ p->conn = softnic_conn_init(&conn_params);
+ if (p->conn == NULL) {
+ softnic_thread_free(p);
+ rte_free(p);
+ return NULL;
+ }
+ }
+
return p;
}
if (p == NULL)
return;
+ if (p->params.conn_port)
+ softnic_conn_free(p->conn);
+
softnic_thread_free(p);
softnic_pipeline_free(p);
softnic_table_action_profile_free(p);
return 0;
}
+static int
+get_uint16(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ if (!value || !extra_args)
+ return -EINVAL;
+
+ *(uint16_t *)extra_args = strtoull(value, NULL, 0);
+
+ return 0;
+}
+
static int
pmd_parse_args(struct pmd_params *p, const char *params)
{
goto out_free;
}
+ /* Connection listening port (optional) */
+ if (rte_kvargs_count(kvlist, PMD_PARAM_CONN_PORT) == 1) {
+ ret = rte_kvargs_process(kvlist, PMD_PARAM_CONN_PORT,
+ &get_uint16, &p->conn_port);
+ if (ret < 0)
+ goto out_free;
+ }
+
/* CPU ID (optional) */
if (rte_kvargs_count(kvlist, PMD_PARAM_CPU_ID) == 1) {
ret = rte_kvargs_process(kvlist, PMD_PARAM_CPU_ID,
RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
PMD_PARAM_FIRMWARE "=<string> "
+ PMD_PARAM_CONN_PORT "=<uint16> "
PMD_PARAM_CPU_ID "=<uint32> "
PMD_PARAM_TM_N_QUEUES "=<uint32> "
PMD_PARAM_TM_QSIZE0 "=<uint32> "
if (pmd_softnic_logtype >= 0)
rte_log_set_level(pmd_softnic_logtype, RTE_LOG_NOTICE);
}
+
+int
+rte_pmd_softnic_manage(uint16_t port_id)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+ struct pmd_internals *softnic;
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
+#endif
+
+ softnic = dev->data->dev_private;
+
+ softnic_conn_poll_for_conn(softnic->conn);
+
+ softnic_conn_poll_for_msg(softnic->conn);
+
+ return 0;
+}
#define SOFTNIC_FIRMWARE "firmware.cli"
#endif
+/** TCP connection port (0 = no connectivity). */
+#ifndef SOFTNIC_CONN_PORT
+#define SOFTNIC_CONN_PORT 0
+#endif
+
/** NUMA node ID. */
#ifndef SOFTNIC_CPU_ID
#define SOFTNIC_CPU_ID 0
int
rte_pmd_softnic_run(uint16_t port_id);
+/**
+ * Soft NIC manage.
+ *
+ * @param port_id
+ * Port ID of the Soft NIC device.
+ * @return
+ * Zero on success, error code otherwise.
+ */
+int __rte_experimental
+rte_pmd_softnic_manage(uint16_t port_id);
+
#ifdef __cplusplus
}
#endif
#include <rte_tm_driver.h>
#include "rte_eth_softnic.h"
+#include "conn.h"
#define NAME_SIZE 64
struct pmd_params {
const char *name;
const char *firmware;
+ uint16_t conn_port;
uint32_t cpu_id;
/** Traffic Management (TM) */
struct tm_internals tm; /**< Traffic Management */
} soft;
+ struct softnic_conn *conn;
struct softnic_mempool_list mempool_list;
struct softnic_swq_list swq_list;
struct softnic_link_list link_list;
local: *;
};
+
+EXPERIMENTAL {
+ global:
+
+ rte_pmd_softnic_manage;
+};