Skip to content

Commit

Permalink
net: shell: Add net-sockets command
Browse files Browse the repository at this point in the history
The new "net sockets" command will utilize the object core
support to track and show information about BSD sockets that
are created in the system. This command is able to show info
for all network sockets (native, offloaded etc) in the system.

Example of the output of the new command:

uart:~$ net sockets
 Creator  Name       Flags  FD   Lifetime (ms) Sent  Received

    main  af_inet46  6ST    0    3260          819   498
    main  af_inet46  4ST    1    2110          469   142
    main  af_inet46  6DU    2    2110          9941  9941
    main  af_inet46  4DU    3    2110          1375  621

4 active sockets found.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
  • Loading branch information
jukkar committed Oct 23, 2023
1 parent 9786396 commit f405364
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/connectivity/networking/api/net_shell.rst
Expand Up @@ -38,6 +38,9 @@ The following net-shell commands are implemented:
"net ping", "Ping a network host."
"net route", "Show IPv6 network routes. Only available if
:kconfig:option:`CONFIG_NET_ROUTE` is set."
"net sockets", "Show network socket information and statistics. Only available if
:kconfig:option:`CONFIG_NET_SOCKETS_OBJ_CORE` and :kconfig:option:`CONFIG_OBJ_CORE`
are set."
"net stats", "Show network statistics."
"net tcp", "Connect/send data/close TCP connection. Only available if
:kconfig:option:`CONFIG_NET_TCP` is set."
Expand Down
1 change: 1 addition & 0 deletions subsys/net/lib/shell/CMakeLists.txt
Expand Up @@ -23,6 +23,7 @@ zephyr_library_sources(pkt.c)
zephyr_library_sources(ppp.c)
zephyr_library_sources(resume.c)
zephyr_library_sources(route.c)
zephyr_library_sources(sockets.c)
zephyr_library_sources(stats.c)
zephyr_library_sources(suspend.c)
zephyr_library_sources(tcp.c)
Expand Down
130 changes: 130 additions & 0 deletions subsys/net/lib/shell/sockets.c
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_shell);

#include "common.h"
#include <zephyr/net/socket.h>

#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
struct socket_info {
int opened;
int closed;
};

int walk_sockets(struct k_obj_core *obj_core, void *user_data)
{
#if defined(CONFIG_THREAD_NAME)
#define THREAD_NAME_LEN CONFIG_THREAD_MAX_NAME_LEN
#else
#define THREAD_NAME_LEN 16
#endif
struct sock_obj_type_raw_stats stats = { 0 };
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
struct socket_info *count = data->user_data;
char thread_name[THREAD_NAME_LEN + 1];
char fd[5] = { 0 };
struct sock_obj *obj;
int lifetime;
int ret;

obj = CONTAINER_OF(obj_core, struct sock_obj, obj_core);

if (k_thread_name_copy(obj->creator, thread_name,
sizeof(thread_name) - 1) < 0) {
snprintk(thread_name, sizeof(thread_name) - 1, "%p",
obj->creator);
}

thread_name[sizeof(thread_name) - 1] = '\0';

ret = k_obj_core_stats_raw(K_OBJ_CORE(obj),
&stats, sizeof(stats));
if (ret != 0) {
PR_INFO("Failed to get statistics (%d)\n", ret);
}

if (obj->fd < 0) {
/* Already closed socket. The create time contains the
* actual lifetime as calculated in close()
*/
lifetime = obj->create_time;
strncat(fd, "C", 1);
count->closed++;
} else {
lifetime = k_ticks_to_ms_ceil32(sys_clock_tick_get() -
obj->create_time);
snprintk(fd, sizeof(fd), "%d", obj->fd);
count->opened++;
}

PR("%16s %-12s %c%c%c\t%-5s%-13d %-10" PRId64 "%-10" PRId64 "\n",
thread_name, obj->reg->name,
obj->socket_family == AF_INET6 ? '6' :
(obj->socket_family ? '4' : ' '),
obj->socket_type == SOCK_DGRAM ? 'D' :
(obj->socket_type == SOCK_STREAM ? 'S' :
(obj->socket_type == SOCK_RAW ? 'R' : ' ')),
obj->socket_proto == IPPROTO_UDP ? 'U' :
(obj->socket_proto == IPPROTO_TCP ? 'T' : ' '),
fd, lifetime, stats.sent, stats.received);

return 0;
}
#endif /* CONFIG_NET_SOCKETS_OBJ_CORE */

static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
struct net_shell_user_data user_data;
struct k_obj_type *obj_type;
struct socket_info count = { 0 };

user_data.sh = sh;
user_data.user_data = &count;

PR("%16s %-12s %-5s\t%-5s%-14s %-10s%-10s\n",
"Creator", "Name", "Flags", "FD", "Lifetime (ms)", "Sent",
"Received");
PR("\n");

obj_type = k_obj_type_find(K_OBJ_TYPE_SOCK);
k_obj_type_walk_unlocked(obj_type, walk_sockets, (void *)&user_data);

if (count.opened == 0 && count.closed == 0) {
PR("No sockets found.\n");
} else {
if (count.opened > 0) {
PR("\n%d active socket%s found.\n", count.opened,
count.opened == 1 ? "" : "s");
}

if (count.closed > 0) {
if (count.opened == 0) {
PR("\n");
}

PR("%d closed socket%s found.\n", count.closed,
count.closed == 1 ? "" : "s");
}
}
#else
ARG_UNUSED(argc);
ARG_UNUSED(argv);

PR_INFO("Set %s to enable %s support.\n",
"CONFIG_OBJ_CORE and CONFIG_NET_SOCKETS_OBJ_CORE",
"socket information");
#endif

return 0;
}

SHELL_SUBCMD_ADD((net), sockets, NULL,
"Show network sockets.",
cmd_net_sockets, 1, 0);

0 comments on commit f405364

Please sign in to comment.