From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1F73F431DE; Mon, 23 Oct 2023 09:03:56 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0F6A2402D9; Mon, 23 Oct 2023 09:03:56 +0200 (CEST) Received: from mail-qt1-f178.google.com (mail-qt1-f178.google.com [209.85.160.178]) by mails.dpdk.org (Postfix) with ESMTP id 89B09402D8 for ; Mon, 23 Oct 2023 09:03:54 +0200 (CEST) Received: by mail-qt1-f178.google.com with SMTP id d75a77b69052e-41cc44736f2so20785751cf.3 for ; Mon, 23 Oct 2023 00:03:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698044634; x=1698649434; darn=dpdk.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=nbNOlhaFtyJeR1dHBS6q15C6/YcUDX1QAPeX/69fGE0=; b=klUmgMn6QbUMdCP4y8mNx9TdXSiyAmQHcAPRRWosCdZ5WDODYKra48wjowhDdnPxb3 YQIGhAiBya7F5vgxl5HMtFixJLSXUrgat07BbQ6dbHRrnw1djy5mCVCDfem3rsMxk3s2 zIdZWPRwW1iqBS0p5yUcRI2KkL9w4E5rgOTZSzfM8KGxb+PXh/VSJCDSzqUrRXSwqCJe YFtwLHd9vKKUlebZDOnn5GU8MjGFdjmBmBBXpByzDsLSoblV/UI4/BZL05tDvFj57W3y 36T1XUz6JndPvEGFnN5Adp5nFVS/0zRAdPQB0xNsdyAiVuvRwPUMBY6YfZi7Q/U4mZN4 zl8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698044634; x=1698649434; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=nbNOlhaFtyJeR1dHBS6q15C6/YcUDX1QAPeX/69fGE0=; b=XXiflkJkmigOUDwVTFxfM7x+DXlaFtzmiK/LWpezHF/abQ49WMgnB8HeyXKQJ+FS80 ZQPJSryveRY3koAD8JAuJwUFiqmOpWkaMUwVrbMjWnZ+vNeKHybdFvSv2KqWZPk8mQ7s h5pnJgeVjdiYQeXlroNxLfXA4taPIJXnspILKIg4KHRDaR+cnRNk0b5AG6h+lRgYml5L kbKHN+p8JF4/NAO0hwkP8cYq49PuWasWuNRLZKEAJYoyEuDDXFNMSnz4V/35S0uHAmzr OaIeASdb0yEkBWEM5Iv389v/hrWcxu5IuMRihuNOF5LHrU50CzEui20N2ONlYDP9yRBN INig== X-Gm-Message-State: AOJu0Yz5saZ6C82c4Pns4B6gAbKY5/EsMEGltudsBfQieF4eVHDa8kRD kBamFyNwnbJjCJ9eElFl8ea1mW+UCrxpHiSDZQQUws/bDv4= X-Google-Smtp-Source: AGHT+IGx94Z5o4hjYH92mZuNaYmM2nkPer3pZ3Ki/MrjpiGvB4hqd3e1e9YnGu69HRMTJ/qZCvl1HBJpvmN5F58MRBY= X-Received: by 2002:ac8:5fc8:0:b0:419:4e1c:6904 with SMTP id k8-20020ac85fc8000000b004194e1c6904mr13513950qta.20.1698044633735; Mon, 23 Oct 2023 00:03:53 -0700 (PDT) MIME-Version: 1.0 References: <20231019105000.520914-13-skori@marvell.com> <20231019173011.1186656-1-skori@marvell.com> <20231019173011.1186656-3-skori@marvell.com> In-Reply-To: <20231019173011.1186656-3-skori@marvell.com> From: Nithin Dabilpuram Date: Mon, 23 Oct 2023 12:33:41 +0530 Message-ID: Subject: Re: [PATCH v11 02/12] app/graph: support telnet connectivity framework To: skori@marvell.com Cc: Rakesh Kudurumalla , dev@dpdk.org, Jerin Jacob Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Acked-By: Nithin Dabilpuram On Fri, Oct 20, 2023 at 3:47=E2=80=AFAM wrote: > > From: Sunil Kumar Kori > > Adds framework to initiate a telnet session with application. > > Some configurations and debug commands are exposed as runtime APIs. > Those commands can be invoked using telnet session. > > Application initiates a telnet server with host address 0.0.0.0 > and port number 8086 by default. > > To make it configurable, "-h" and "-p" options are provided. > Using them user can pass host address and port number on which > application will start telnet server. > > Using same host address and port number, telnet client can connect > to application. > > Syntax to connect with application: > # telnet > > Once session is connected, "graph> " prompt will be available. > Example: > # telnet 10.28.35.207 50000 > Trying 10.28.35.207... > Connected to 10.28.35.207. > Escape character is '^]'. > > Welcome! > > graph> > > Signed-off-by: Sunil Kumar Kori > Signed-off-by: Rakesh Kudurumalla > Acked-by: Jerin Jacob > --- > app/graph/conn.c | 284 +++++++++++++++++++++++++++++++++++++ > app/graph/conn.h | 46 ++++++ > app/graph/main.c | 103 +++++++++++++- > app/graph/meson.build | 1 + > app/graph/module_api.h | 3 + > doc/guides/tools/graph.rst | 38 +++++ > 6 files changed, 470 insertions(+), 5 deletions(-) > create mode 100644 app/graph/conn.c > create mode 100644 app/graph/conn.h > > diff --git a/app/graph/conn.c b/app/graph/conn.c > new file mode 100644 > index 0000000000..44934602c7 > --- /dev/null > +++ b/app/graph/conn.c > @@ -0,0 +1,284 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include "module_api.h" > + > +#define MSG_CMD_TOO_LONG "Command too long." > + > +static int > +data_event_handle(struct conn *conn, int fd_client) > +{ > + ssize_t len, i, rc =3D 0; > + > + /* Read input message */ > + len =3D read(fd_client, conn->buf, conn->buf_size); > + if (len =3D=3D -1) { > + if ((errno =3D=3D EAGAIN) || (errno =3D=3D EWOULDBLOCK)) > + return 0; > + > + return -1; > + } > + > + if (len =3D=3D 0) > + return rc; > + > + /* Handle input messages */ > + for (i =3D 0; i < len; i++) { > + if (conn->buf[i] =3D=3D '\n') { > + size_t n; > + > + conn->msg_in[conn->msg_in_len] =3D 0; > + conn->msg_out[0] =3D 0; > + > + conn->msg_handle(conn->msg_in, conn->msg_out, con= n->msg_out_len_max, > + conn->msg_handle_arg); > + > + n =3D strlen(conn->msg_out); > + if (n) { > + rc =3D write(fd_client, conn->msg_out, n)= ; > + if (rc =3D=3D -1) > + goto exit; > + } > + > + conn->msg_in_len =3D 0; > + } else if (conn->msg_in_len < conn->msg_in_len_max) { > + conn->msg_in[conn->msg_in_len] =3D conn->buf[i]; > + conn->msg_in_len++; > + } else { > + rc =3D write(fd_client, MSG_CMD_TOO_LONG, strlen(= MSG_CMD_TOO_LONG)); > + if (rc =3D=3D -1) > + goto exit; > + > + conn->msg_in_len =3D 0; > + } > + } > + > + /* Write prompt */ > + rc =3D write(fd_client, conn->prompt, strlen(conn->prompt)); > + rc =3D (rc =3D=3D -1) ? -1 : 0; > + > +exit: > + return rc; > +} > + > +static int > +control_event_handle(struct conn *conn, int fd_client) > +{ > + int rc; > + > + rc =3D epoll_ctl(conn->fd_client_group, EPOLL_CTL_DEL, fd_client,= NULL); > + if (rc =3D=3D -1) > + goto exit; > + > + rc =3D close(fd_client); > + if (rc =3D=3D -1) > + goto exit; > + > + rc =3D 0; > + > +exit: > + return rc; > +} > + > +struct conn * > +conn_init(struct conn_params *p) > +{ > + int fd_server, fd_client_group, rc; > + struct sockaddr_in server_address; > + struct conn *conn =3D NULL; > + int reuse =3D 1; > + > + memset(&server_address, 0, sizeof(server_address)); > + > + /* Check input arguments */ > + if ((p =3D=3D NULL) || (p->welcome =3D=3D NULL) || (p->prompt =3D= =3D NULL) || (p->addr =3D=3D NULL) || > + (p->buf_size =3D=3D 0) || (p->msg_in_len_max =3D=3D 0) || (p-= >msg_out_len_max =3D=3D 0) || > + (p->msg_handle =3D=3D NULL)) > + goto exit; > + > + rc =3D inet_aton(p->addr, &server_address.sin_addr); > + if (rc =3D=3D 0) > + goto exit; > + > + /* Memory allocation */ > + conn =3D calloc(1, sizeof(struct conn)); > + if (conn =3D=3D NULL) > + goto exit; > + > + conn->welcome =3D calloc(1, CONN_WELCOME_LEN_MAX + 1); > + conn->prompt =3D calloc(1, CONN_PROMPT_LEN_MAX + 1); > + conn->buf =3D calloc(1, p->buf_size); > + conn->msg_in =3D calloc(1, p->msg_in_len_max + 1); > + conn->msg_out =3D calloc(1, p->msg_out_len_max + 1); > + > + if ((conn->welcome =3D=3D NULL) || (conn->prompt =3D=3D NULL) || = (conn->buf =3D=3D NULL) || > + (conn->msg_in =3D=3D NULL) || (conn->msg_out =3D=3D NULL)) { > + conn_free(conn); > + conn =3D NULL; > + goto exit; > + } > + > + /* Server socket */ > + server_address.sin_family =3D AF_INET; > + server_address.sin_port =3D htons(p->port); > + > + fd_server =3D socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); > + if (fd_server =3D=3D -1) { > + conn_free(conn); > + conn =3D NULL; > + goto exit; > + } > + > + if (setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, (const char *= )&reuse, > + sizeof(reuse)) < 0) > + goto free; > + > + rc =3D bind(fd_server, (struct sockaddr *)&server_address, sizeof= (server_address)); > + if (rc =3D=3D -1) > + goto free; > + > + rc =3D listen(fd_server, 16); > + if (rc =3D=3D -1) > + goto free; > + > + /* Client group */ > + fd_client_group =3D epoll_create(1); > + if (fd_client_group =3D=3D -1) > + goto free; > + > + /* Fill in */ > + rte_strscpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); > + rte_strscpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); > + conn->buf_size =3D p->buf_size; > + conn->msg_in_len_max =3D p->msg_in_len_max; > + conn->msg_out_len_max =3D p->msg_out_len_max; > + conn->msg_in_len =3D 0; > + conn->fd_server =3D fd_server; > + conn->fd_client_group =3D fd_client_group; > + conn->msg_handle =3D p->msg_handle; > + conn->msg_handle_arg =3D p->msg_handle_arg; > + > +exit: > + return conn; > +free: > + conn_free(conn); > + close(fd_server); > + conn =3D NULL; > + return conn; > +} > + > +void > +conn_free(struct conn *conn) > +{ > + if (conn =3D=3D 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_req_poll(struct conn *conn) > +{ > + struct sockaddr_in client_address; > + socklen_t client_address_length; > + struct epoll_event event; > + int fd_client, rc; > + > + /* Check input arguments */ > + if (conn =3D=3D NULL) > + return -1; > + > + /* Server socket */ > + client_address_length =3D sizeof(client_address); > + fd_client =3D accept4(conn->fd_server, (struct sockaddr *)&client= _address, > + &client_address_length, SOCK_NONBLOCK); > + if (fd_client =3D=3D -1) { > + if ((errno =3D=3D EAGAIN) || (errno =3D=3D EWOULDBLOCK)) > + return 0; > + > + return -1; > + } > + > + /* Client group */ > + event.events =3D EPOLLIN | EPOLLRDHUP | EPOLLHUP; > + event.data.fd =3D fd_client; > + > + rc =3D epoll_ctl(conn->fd_client_group, EPOLL_CTL_ADD, fd_client,= &event); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + /* Client */ > + rc =3D write(fd_client, conn->welcome, strlen(conn->welcome)); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + rc =3D write(fd_client, conn->prompt, strlen(conn->prompt)); > + if (rc =3D=3D -1) { > + close(fd_client); > + goto exit; > + } > + > + rc =3D 0; > + > +exit: > + return rc; > +} > + > +int > +conn_msg_poll(struct conn *conn) > +{ > + int fd_client, rc, rc_data =3D 0, rc_control =3D 0; > + struct epoll_event event; > + > + /* Check input arguments */ > + if (conn =3D=3D NULL) > + return -1; > + > + /* Client group */ > + rc =3D epoll_wait(conn->fd_client_group, &event, 1, 0); > + if ((rc =3D=3D -1) || rc =3D=3D 0) > + return rc; > + > + fd_client =3D event.data.fd; > + > + /* Data available */ > + if (event.events & EPOLLIN) > + rc_data =3D data_event_handle(conn, fd_client); > + > + /* Control events */ > + if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) > + rc_control =3D control_event_handle(conn, fd_client); > + > + if (rc_data || rc_control) > + return -1; > + > + return 0; > +} > diff --git a/app/graph/conn.h b/app/graph/conn.h > new file mode 100644 > index 0000000000..770964cf4c > --- /dev/null > +++ b/app/graph/conn.h > @@ -0,0 +1,46 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2023 Marvell. > + */ > + > +#ifndef APP_GRAPH_CONN_H > +#define APP_GRAPH_CONN_H > + > +#define CONN_WELCOME_LEN_MAX 1024 > +#define CONN_PROMPT_LEN_MAX 16 > + > +typedef void (*conn_msg_handle_t)(char *msg_in, char *msg_out, size_t ms= g_out_len_max, void *arg); > + > +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_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_req_poll(struct conn *conn); > +int conn_msg_poll(struct conn *conn); > + > +#endif > diff --git a/app/graph/main.c b/app/graph/main.c > index 734a94444e..96548f49e7 100644 > --- a/app/graph/main.c > +++ b/app/graph/main.c > @@ -2,6 +2,7 @@ > * Copyright(c) 2023 Marvell. > */ > > +#include > #include > #include > #include > @@ -11,19 +12,33 @@ > #include > #include > > +#include > #include > #include > > #include "module_api.h" > > volatile bool force_quit; > +struct conn *conn; > > -static const char usage[] =3D "%s EAL_ARGS -- -s SCRIPT " > +static const char usage[] =3D "%s EAL_ARGS -- -s SCRIPT [-h HOST] [-p PO= RT] " > "[--help]\n"; > > static struct app_params { > + struct conn_params conn; > char *script_name; > } app =3D { > + .conn =3D { > + .welcome =3D "\nWelcome!\n\n", > + .prompt =3D "graph> ", > + .addr =3D "0.0.0.0", > + .port =3D 8086, > + .buf_size =3D 1024 * 1024, > + .msg_in_len_max =3D 1024, > + .msg_out_len_max =3D 1024 * 1024, > + .msg_handle =3D cli_process, > + .msg_handle_arg =3D NULL, /* set later. */ > + }, > .script_name =3D NULL, > }; > > @@ -42,7 +57,7 @@ app_args_parse(int argc, char **argv) > struct option lgopts[] =3D { > {"help", 0, 0, 'H'}, > }; > - int s_present, n_args, i; > + int h_present, p_present, s_present, n_args, i; > char *app_name =3D argv[0]; > int opt, option_index; > > @@ -59,10 +74,46 @@ app_args_parse(int argc, char **argv) > return 0; > > /* Parse args */ > + h_present =3D 0; > + p_present =3D 0; > s_present =3D 0; > > - while ((opt =3D getopt_long(argc, argv, "s:", lgopts, &option_ind= ex)) !=3D EOF) { > + while ((opt =3D getopt_long(argc, argv, "h:p:s:", lgopts, &option= _index)) !=3D EOF) { > switch (opt) { > + case 'h': > + if (h_present) { > + printf("Error: Multiple -h arguments\n"); > + return -1; > + } > + h_present =3D 1; > + > + if (!strlen(optarg)) { > + printf("Error: Argument for -h not provid= ed\n"); > + return -1; > + } > + > + app.conn.addr =3D strdup(optarg); > + if (app.conn.addr =3D=3D NULL) { > + printf("Error: Not enough memory\n"); > + return -1; > + } > + break; > + > + case 'p': > + if (p_present) { > + printf("Error: Multiple -p arguments\n"); > + return -1; > + } > + p_present =3D 1; > + > + if (!strlen(optarg)) { > + printf("Error: Argument for -p not provid= ed\n"); > + return -1; > + } > + > + app.conn.port =3D (uint16_t)strtoul(optarg, NULL,= 10); > + break; > + > case 's': > if (s_present) { > printf("Error: Multiple -s arguments\n"); > @@ -93,6 +144,26 @@ app_args_parse(int argc, char **argv) > return 0; > } > > +bool > +app_graph_exit(void) > +{ > + struct timeval tv; > + fd_set fds; > + int ret; > + char c; > + > + FD_ZERO(&fds); > + FD_SET(0, &fds); > + tv.tv_sec =3D 0; > + tv.tv_usec =3D 100; > + ret =3D select(1, &fds, NULL, NULL, &tv); > + if ((ret < 0 && errno =3D=3D EINTR) || (ret =3D=3D 1 && read(0, &= c, 1) > 0)) > + return true; > + else > + return false; > + > +} > + > int > main(int argc, char **argv) > { > @@ -118,10 +189,32 @@ main(int argc, char **argv) > > /* Script */ > if (app.script_name) { > - cli_script_process(app.script_name, 0, > - 0, NULL); > + cli_script_process(app.script_name, app.conn.msg_in_len_m= ax, > + app.conn.msg_out_len_max, NULL); > + } > + > + /* Connectivity */ > + app.conn.msg_handle_arg =3D NULL; > + conn =3D conn_init(&app.conn); > + if (!conn) { > + printf("Error: Connectivity initialization failed\n"); > + goto exit; > + }; > + > + rte_delay_ms(1); > + printf("Press enter to exit\n"); > + > + /* Dispatch loop */ > + while (!force_quit) { > + conn_req_poll(conn); > + > + conn_msg_poll(conn); > + if (app_graph_exit()) > + force_quit =3D true; > } > > +exit: > + conn_free(conn); > cli_exit(); > rte_eal_cleanup(); > return 0; > diff --git a/app/graph/meson.build b/app/graph/meson.build > index ed33a04476..c8d2b41b69 100644 > --- a/app/graph/meson.build > +++ b/app/graph/meson.build > @@ -11,5 +11,6 @@ endif > deps +=3D ['graph', 'eal', 'lpm', 'ethdev', 'node', 'cmdline'] > sources =3D files( > 'cli.c', > + 'conn.c', > 'main.c', > ) > diff --git a/app/graph/module_api.h b/app/graph/module_api.h > index 372aeae7e3..9826303f0c 100644 > --- a/app/graph/module_api.h > +++ b/app/graph/module_api.h > @@ -7,10 +7,13 @@ > > #include > #include > + > #include "cli.h" > +#include "conn.h" > /* > * Externs > */ > extern volatile bool force_quit; > > +bool app_graph_exit(void); > #endif > diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst > index cb005e7856..943f915049 100644 > --- a/doc/guides/tools/graph.rst > +++ b/doc/guides/tools/graph.rst > @@ -39,6 +39,16 @@ Application Options > > Following are the application command-line options: > > +* ``-h`` > + > + Set the host IPv4 address over which telnet session can be opene= d. > + It is an optional parameter. Default host address is 0.0.0.0. > + > +* ``-p`` > + > + Set the L4 port number over which telnet session can be opened. > + It is an optional parameter. Default port is 8086. > + > * ``-s`` > > Script name with absolute path which specifies the use case. It = is > @@ -67,7 +77,35 @@ file to express the requested use case configuration. > Runtime configuration > --------------------- > > +Application allows some configuration to be modified at runtime using a = telnet session. > +Application initiates a telnet server with host address ``0.0.0.0`` and = port number ``8086`` > +by default. > + > +if user passes ``-h`` and ``-p`` options while running application then = corresponding > +IP address and port number will be used for telnet session. > + > +After successful launch of application, client can connect to applicatio= n using given > +host & port and console will be accessed with prompt ``graph>``. > + > +Command to access a telnet session > + > +.. code-block:: console > + > + telnet > + > +Example: ``dpdk-graph`` is started with -h 10.28.35.207 and -p 50000 the= n > + > +.. code-block:: console > + > + $ telnet 10.28.35.207 50000 > + Trying 10.28.35.207... > + Connected to 10.28.35.207. > + Escape character is '^]'. > + > + Welcome! > > + graph> > + graph> > Created graph for use case > -------------------------- > > -- > 2.25.1 >