diff mbox series

[dpdk-dev,13/21] net/softnic: add connection agent

Message ID 20180608124155.140663-14-jasvinder.singh@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Cristian Dumitrescu
Headers show
Series [dpdk-dev,01/21] net/softnic: restructuring | expand

Checks

Context Check Description
ci/Intel-compilation fail Compilation issues
ci/checkpatch warning coding style issues

Commit Message

Singh, Jasvinder June 8, 2018, 12:41 p.m. UTC
Add connection agent to enable connectivity with external agen
(e.g. telnet, netcat, Python script, etc).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 drivers/net/softnic/Makefile                       |   1 +
 drivers/net/softnic/conn.c                         | 332 +++++++++++++++++++++
 drivers/net/softnic/conn.h                         |  49 +++
 drivers/net/softnic/rte_eth_softnic.c              |  79 +++++
 drivers/net/softnic/rte_eth_softnic.h              |  12 +
 drivers/net/softnic/rte_eth_softnic_internals.h    |   3 +
 .../net/softnic/rte_pmd_eth_softnic_version.map    |   7 +
 7 files changed, 483 insertions(+)
 create mode 100644 drivers/net/softnic/conn.c
 create mode 100644 drivers/net/softnic/conn.h
diff mbox series

Patch

diff --git a/drivers/net/softnic/Makefile b/drivers/net/softnic/Makefile
index 5d3cd68..6bc572d 100644
--- a/drivers/net/softnic/Makefile
+++ b/drivers/net/softnic/Makefile
@@ -34,6 +34,7 @@  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
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += conn.c
 
 #
 # Export include files
diff --git a/drivers/net/softnic/conn.c b/drivers/net/softnic/conn.c
new file mode 100644
index 0000000..d569944
--- /dev/null
+++ b/drivers/net/softnic/conn.c
@@ -0,0 +1,332 @@ 
+/* 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 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;
+	conn_msg_handle_t msg_handle;
+	void *msg_handle_arg;
+};
+
+struct conn *
+conn_init(struct conn_params *p)
+{
+	struct sockaddr_in server_address;
+	struct 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 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)) {
+		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) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = bind(fd_server,
+		(struct sockaddr *) &server_address,
+		sizeof(server_address));
+	if (status == -1) {
+		conn_free(conn);
+		close(fd_server);
+		return NULL;
+	}
+
+	status = listen(fd_server, 16);
+	if (status == -1) {
+		conn_free(conn);
+		close(fd_server);
+		return NULL;
+	}
+
+	/* Client group */
+	fd_client_group = epoll_create(1);
+	if (fd_client_group == -1) {
+		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
+conn_free(struct 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
+conn_poll_for_conn(struct 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 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 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
+conn_poll_for_msg(struct 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;
+}
diff --git a/drivers/net/softnic/conn.h b/drivers/net/softnic/conn.h
new file mode 100644
index 0000000..c82eb8f
--- /dev/null
+++ b/drivers/net/softnic/conn.h
@@ -0,0 +1,49 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct 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 (*conn_msg_handle_t)(char *msg_in,
+	char *msg_out,
+	size_t msg_out_len_max,
+	void *arg);
+
+struct 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;
+	conn_msg_handle_t msg_handle;
+	void *msg_handle_arg;
+};
+
+struct conn *
+conn_init(struct conn_params *p);
+
+void
+conn_free(struct conn *conn);
+
+int
+conn_poll_for_conn(struct conn *conn);
+
+int
+conn_poll_for_msg(struct conn *conn);
+
+#endif
diff --git a/drivers/net/softnic/rte_eth_softnic.c b/drivers/net/softnic/rte_eth_softnic.c
index 321813b..9641725 100644
--- a/drivers/net/softnic/rte_eth_softnic.c
+++ b/drivers/net/softnic/rte_eth_softnic.c
@@ -19,14 +19,35 @@ 
 #include "rte_eth_softnic_internals.h"
 
 #define PMD_PARAM_SCRIPT					"script"
+#define PMD_PARAM_CONN_PORT				"conn_port"
 #define PMD_PARAM_CPU_ID					"cpu_id"
 
 static const char *pmd_valid_args[] = {
 	PMD_PARAM_SCRIPT,
+	PMD_PARAM_CONN_PORT,
 	PMD_PARAM_CPU_ID,
 	NULL
 };
 
+static const char welcome[] =
+	"\n"
+	"Welcome to Soft NIC!\n"
+	"\n";
+
+static const char prompt[] = "softnic> ";
+
+struct 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 = 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,
@@ -225,6 +246,21 @@  pmd_init(struct pmd_params *params)
 		return NULL;
 	}
 
+	if (params->conn_port) {
+		struct 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 = conn_init(&conn_params);
+		if (p->conn == NULL) {
+			thread_free(p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
 	return p;
 }
 
@@ -234,6 +270,9 @@  pmd_free(struct pmd_internals *p)
 	if (p == NULL)
 		return;
 
+	if (p->params.conn_port)
+		conn_free(p->conn);
+
 	thread_free(p);
 	pipeline_free(p);
 	table_action_profile_free(p);
@@ -312,6 +351,17 @@  get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
 }
 
 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)
 {
 	struct rte_kvargs *kvlist;
@@ -324,6 +374,7 @@  pmd_parse_args(struct pmd_params *p, const char *params)
 	/* Set default values */
 	memset(p, 0, sizeof(*p));
 	p->script = "firmware.cli";
+	p->conn_port = 0;
 	p->cpu_id = 0;
 
 	/* script (optional) */
@@ -334,6 +385,14 @@  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,
@@ -420,6 +479,7 @@  static struct rte_vdev_driver pmd_softnic_drv = {
 RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
 RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
 	PMD_PARAM_SCRIPT "=<string> "
+	PMD_PARAM_CONN_PORT "=<uint16> "
 	PMD_PARAM_CPU_ID "=<uint32>");
 
 RTE_INIT(pmd_softnic_init_log);
@@ -430,3 +490,22 @@  pmd_softnic_init_log(void)
 	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;
+
+	conn_poll_for_conn(softnic->conn);
+
+	conn_poll_for_msg(softnic->conn);
+
+	return 0;
+}
diff --git a/drivers/net/softnic/rte_eth_softnic.h b/drivers/net/softnic/rte_eth_softnic.h
index 415b4c8..66df239 100644
--- a/drivers/net/softnic/rte_eth_softnic.h
+++ b/drivers/net/softnic/rte_eth_softnic.h
@@ -23,6 +23,18 @@  extern "C" {
 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_pmd_softnic_manage(uint16_t port_id);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index cf3c087..4b680dc 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -22,6 +22,7 @@ 
 #include <rte_tm_driver.h>
 
 #include "rte_eth_softnic.h"
+#include "conn.h"
 
 #define NAME_SIZE                                            64
 
@@ -32,6 +33,7 @@ 
 struct pmd_params {
 	const char *name;
 	const char *script;
+	uint16_t conn_port;
 	uint32_t cpu_id;
 
 	/** Parameters for the soft device (to be created) */
@@ -508,6 +510,7 @@  struct pmd_internals {
 		struct tm_internals tm; /**< Traffic Management */
 	} soft;
 
+	struct conn *conn;
 	struct mempool_list mempool_list;
 	struct swq_list swq_list;
 	struct link_list link_list;
diff --git a/drivers/net/softnic/rte_pmd_eth_softnic_version.map b/drivers/net/softnic/rte_pmd_eth_softnic_version.map
index fb2cb68..ac501ff 100644
--- a/drivers/net/softnic/rte_pmd_eth_softnic_version.map
+++ b/drivers/net/softnic/rte_pmd_eth_softnic_version.map
@@ -5,3 +5,10 @@  DPDK_17.11 {
 
 	local: *;
 };
+
+DPDK_18.08 {
+	global:
+
+	rte_pmd_softnic_manage;
+
+} DPDK_17.11;