net: sockets: Add object core support to sockets

Use the generic object core support to track network sockets
and their statistics.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2023-09-13 15:09:28 +03:00 committed by Carles Cufí
parent 03e2b6aee2
commit 7d9f2ad2ca
7 changed files with 390 additions and 15 deletions

View file

@ -1105,6 +1105,12 @@ struct net_socket_register {
bool is_offloaded;
bool (*is_supported)(int family, int type, int proto);
int (*handler)(int family, int type, int proto);
#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
/* Store also the name of the socket type in order to be able to
* print it later.
*/
const char * const name;
#endif
};
#define NET_SOCKET_DEFAULT_PRIO CONFIG_NET_SOCKETS_PRIORITY_DEFAULT
@ -1112,6 +1118,15 @@ struct net_socket_register {
#define NET_SOCKET_GET_NAME(socket_name, prio) \
__net_socket_register_##prio##_##socket_name
#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
#define K_OBJ_TYPE_SOCK K_OBJ_TYPE_ID_GEN("SOCK")
#define NET_SOCKET_REGISTER_NAME(_name) \
.name = STRINGIFY(_name),
#else
#define NET_SOCKET_REGISTER_NAME(_name)
#endif
#define _NET_SOCKET_REGISTER(socket_name, prio, _family, _is_supported, _handler, _is_offloaded) \
static const STRUCT_SECTION_ITERABLE(net_socket_register, \
NET_SOCKET_GET_NAME(socket_name, prio)) = { \
@ -1119,6 +1134,7 @@ struct net_socket_register {
.is_offloaded = _is_offloaded, \
.is_supported = _is_supported, \
.handler = _handler, \
NET_SOCKET_REGISTER_NAME(socket_name) \
}
#define NET_SOCKET_REGISTER(socket_name, prio, _family, _is_supported, _handler) \

View file

@ -141,7 +141,25 @@ static inline void net_coap_init(void)
}
#endif
#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
struct sock_obj_type_raw_stats {
uint64_t sent;
uint64_t received;
};
struct sock_obj {
struct net_socket_register *reg;
uint64_t create_time; /* in ticks */
k_tid_t creator;
int fd;
int socket_family;
int socket_type;
int socket_proto;
bool init_done;
struct k_obj_core obj_core;
struct sock_obj_type_raw_stats stats;
};
#endif /* CONFIG_NET_SOCKETS_OBJ_CORE */
#if defined(CONFIG_NET_GPTP)
/**

View file

@ -25,6 +25,7 @@ zephyr_sources_ifdef(CONFIG_NET_SOCKETS_PACKET sockets_packet.c)
zephyr_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c)
zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c)
zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER socket_dispatcher.c)
zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OBJ_CORE socket_obj_core.c)
if(CONFIG_NET_SOCKETS_NET_MGMT)
zephyr_sources(sockets_net_mgmt.c)

View file

@ -311,4 +311,15 @@ module-str = Log level for BSD sockets compatible API calls
module-help = Enables logging for sockets code.
source "subsys/net/Kconfig.template.log_config.net"
config NET_SOCKETS_OBJ_CORE
bool "Object core socket support [EXPERIMENTAL]"
depends on OBJ_CORE
select OBJ_CORE_STATS
select EXPERIMENTAL
help
Select this if you want to use object core with socket API to get
network socket information and statistics via object core.
The net-shell "net sockets" command will use this functionality
to show the socket information.
endif # NET_SOCKETS

View file

@ -0,0 +1,244 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Object core support for sockets */
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL);
#include <zephyr/kernel.h>
#include "sockets_internal.h"
#include "../../ip/net_private.h"
static struct k_obj_type sock_obj_type;
static K_MUTEX_DEFINE(sock_obj_mutex);
/* Allocate some extra socket objects so that we can track
* closed sockets and get some historical statistics.
*/
static struct sock_obj sock_objects[CONFIG_POSIX_MAX_FDS * 2] = {
[0 ... ((CONFIG_POSIX_MAX_FDS * 2) - 1)] = {
.fd = -1,
.init_done = false,
}
};
static void sock_obj_core_init_and_link(struct sock_obj *sock);
static int sock_obj_core_stats_reset(struct k_obj_core *obj);
static int sock_obj_stats_raw(struct k_obj_core *obj_core, void *stats);
static int sock_obj_core_get_reg_and_proto(int sock,
struct net_socket_register **reg);
struct k_obj_core_stats_desc sock_obj_type_stats_desc = {
.raw_size = sizeof(struct sock_obj_type_raw_stats),
.raw = sock_obj_stats_raw,
.reset = sock_obj_core_stats_reset,
.disable = NULL, /* Stats gathering is always on */
.enable = NULL, /* Stats gathering is always on */
};
static void set_fields(struct sock_obj *obj, int fd,
struct net_socket_register *reg,
int family, int type, int proto)
{
obj->fd = fd;
obj->socket_family = family;
obj->socket_type = type;
obj->socket_proto = proto;
obj->reg = reg;
obj->creator = k_current_get();
obj->create_time = sys_clock_tick_get();
}
static void sock_obj_core_init_and_link(struct sock_obj *sock)
{
static bool type_init_done;
if (!type_init_done) {
z_obj_type_init(&sock_obj_type, K_OBJ_TYPE_SOCK,
offsetof(struct sock_obj, obj_core));
k_obj_type_stats_init(&sock_obj_type, &sock_obj_type_stats_desc);
type_init_done = true;
}
k_obj_core_init_and_link(K_OBJ_CORE(sock), &sock_obj_type);
k_obj_core_stats_register(K_OBJ_CORE(sock), &sock->stats,
sizeof(struct sock_obj_type_raw_stats));
/* If the socket was closed and we re-opened it again, then clear
* the statistics.
*/
if (sock->init_done) {
k_obj_core_stats_reset(K_OBJ_CORE(sock));
}
sock->init_done = true;
}
static int sock_obj_stats_raw(struct k_obj_core *obj_core, void *stats)
{
memcpy(stats, obj_core->stats, sizeof(struct sock_obj_type_raw_stats));
return 0;
}
static int sock_obj_core_stats_reset(struct k_obj_core *obj_core)
{
memset(obj_core->stats, 0, sizeof(struct sock_obj_type_raw_stats));
return 0;
}
static int sock_obj_core_get_reg_and_proto(int sock, struct net_socket_register **reg)
{
int i, ret;
k_mutex_lock(&sock_obj_mutex, K_FOREVER);
for (i = 0; i < ARRAY_SIZE(sock_objects); i++) {
if (sock_objects[i].fd == sock) {
*reg = sock_objects[i].reg;
ret = sock_objects[i].socket_proto;
goto out;
}
}
ret = -ENOENT;
out:
k_mutex_unlock(&sock_obj_mutex);
return ret;
}
int sock_obj_core_alloc(int sock, struct net_socket_register *reg,
int family, int type, int proto)
{
struct sock_obj *obj = NULL;
int ret, i;
if (sock < 0) {
return -EINVAL;
}
k_mutex_lock(&sock_obj_mutex, K_FOREVER);
/* Try not to allocate already closed sockets so that we
* can see historical data.
*/
for (i = 0; i < ARRAY_SIZE(sock_objects); i++) {
if (sock_objects[i].fd < 0) {
if (sock_objects[i].init_done == false) {
obj = &sock_objects[i];
break;
} else if (obj == NULL) {
obj = &sock_objects[i];
}
}
}
if (obj == NULL) {
ret = -ENOENT;
goto out;
}
set_fields(obj, sock, reg, family, type, proto);
sock_obj_core_init_and_link(obj);
ret = 0;
out:
k_mutex_unlock(&sock_obj_mutex);
return ret;
}
int sock_obj_core_alloc_find(int sock, int new_sock, int family, int type)
{
struct net_socket_register *reg = NULL;
int ret;
if (new_sock < 0) {
return -EINVAL;
}
ret = sock_obj_core_get_reg_and_proto(sock, &reg);
if (ret < 0) {
goto out;
}
ret = sock_obj_core_alloc(new_sock, reg, family, type, ret);
if (ret < 0) {
NET_ERR("Cannot allocate core object for socket %d (%d)",
new_sock, ret);
}
out:
return ret;
}
int sock_obj_core_dealloc(int fd)
{
int ret;
k_mutex_lock(&sock_obj_mutex, K_FOREVER);
for (int i = 0; i < ARRAY_SIZE(sock_objects); i++) {
if (sock_objects[i].fd == fd) {
sock_objects[i].fd = -1;
/* Calculate the lifetime of the socket so that
* net-shell can print it for the closed sockets.
*/
sock_objects[i].create_time =
k_ticks_to_ms_ceil32(sys_clock_tick_get() -
sock_objects[i].create_time);
ret = 0;
goto out;
}
}
ret = -ENOENT;
out:
k_mutex_unlock(&sock_obj_mutex);
return ret;
}
void sock_obj_core_update_send_stats(int fd, int bytes)
{
if (bytes > 0) {
k_mutex_lock(&sock_obj_mutex, K_FOREVER);
for (int i = 0; i < ARRAY_SIZE(sock_objects); i++) {
if (sock_objects[i].fd == fd) {
sock_objects[i].stats.sent += bytes;
break;
}
}
k_mutex_unlock(&sock_obj_mutex);
}
}
void sock_obj_core_update_recv_stats(int fd, int bytes)
{
if (bytes > 0) {
k_mutex_lock(&sock_obj_mutex, K_FOREVER);
for (int i = 0; i < ARRAY_SIZE(sock_objects); i++) {
if (sock_objects[i].fd == fd) {
sock_objects[i].stats.received += bytes;
break;
}
}
k_mutex_unlock(&sock_obj_mutex);
}
}

View file

@ -33,12 +33,13 @@ LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL);
#include "sockets_internal.h"
#include "../../ip/tcp_internal.h"
#include "../../ip/net_private.h"
#define SET_ERRNO(x) \
{ int _err = x; if (_err < 0) { errno = -_err; return -1; } }
#define VTABLE_CALL(fn, sock, ...) \
do { \
({ \
const struct socket_op_vtable *vtable; \
struct k_mutex *lock; \
void *obj; \
@ -61,8 +62,8 @@ LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL);
\
k_mutex_unlock(lock); \
\
return ret; \
} while (0)
ret; \
})
const struct socket_op_vtable sock_fd_op_vtable;
@ -217,6 +218,8 @@ static int zsock_socket_internal(int family, int type, int proto)
int z_impl_zsock_socket(int family, int type, int proto)
{
STRUCT_SECTION_FOREACH(net_socket_register, sock_family) {
int ret;
if (sock_family->family != family &&
sock_family->family != AF_UNSPEC) {
continue;
@ -228,7 +231,11 @@ int z_impl_zsock_socket(int family, int type, int proto)
continue;
}
return sock_family->handler(family, type, proto);
ret = sock_family->handler(family, type, proto);
(void)sock_obj_core_alloc(ret, sock_family, family, type, proto);
return ret;
}
errno = EAFNOSUPPORT;
@ -292,6 +299,8 @@ int z_impl_zsock_close(int sock)
z_free_fd(sock);
(void)sock_obj_core_dealloc(sock);
return ret;
}
@ -464,7 +473,7 @@ int zsock_bind_ctx(struct net_context *ctx, const struct sockaddr *addr,
int z_impl_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
VTABLE_CALL(bind, sock, addr, addrlen);
return VTABLE_CALL(bind, sock, addr, addrlen);
}
#ifdef CONFIG_USERSPACE
@ -543,7 +552,7 @@ int zsock_connect_ctx(struct net_context *ctx, const struct sockaddr *addr,
int z_impl_zsock_connect(int sock, const struct sockaddr *addr,
socklen_t addrlen)
{
VTABLE_CALL(connect, sock, addr, addrlen);
return VTABLE_CALL(connect, sock, addr, addrlen);
}
#ifdef CONFIG_USERSPACE
@ -571,7 +580,7 @@ int zsock_listen_ctx(struct net_context *ctx, int backlog)
int z_impl_zsock_listen(int sock, int backlog)
{
VTABLE_CALL(listen, sock, backlog);
return VTABLE_CALL(listen, sock, backlog);
}
#ifdef CONFIG_USERSPACE
@ -668,7 +677,13 @@ int zsock_accept_ctx(struct net_context *parent, struct sockaddr *addr,
int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen)
{
VTABLE_CALL(accept, sock, addr, addrlen);
int new_sock;
new_sock = VTABLE_CALL(accept, sock, addr, addrlen);
(void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM);
return new_sock;
}
#ifdef CONFIG_USERSPACE
@ -832,7 +847,13 @@ ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len,
ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen);
int ret;
ret = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen);
sock_obj_core_update_send_stats(sock, ret);
return ret;
}
#ifdef CONFIG_USERSPACE
@ -911,7 +932,13 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg,
ssize_t z_impl_zsock_sendmsg(int sock, const struct msghdr *msg, int flags)
{
VTABLE_CALL(sendmsg, sock, msg, flags);
int ret;
ret = VTABLE_CALL(sendmsg, sock, msg, flags);
sock_obj_core_update_send_stats(sock, ret);
return ret;
}
#ifdef CONFIG_USERSPACE
@ -1471,7 +1498,13 @@ ssize_t zsock_recvfrom_ctx(struct net_context *ctx, void *buf, size_t max_len,
ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen);
int ret;
ret = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen);
sock_obj_core_update_recv_stats(sock, ret);
return ret;
}
#ifdef CONFIG_USERSPACE
@ -2124,7 +2157,7 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
int z_impl_zsock_getsockopt(int sock, int level, int optname,
void *optval, socklen_t *optlen)
{
VTABLE_CALL(getsockopt, sock, level, optname, optval, optlen);
return VTABLE_CALL(getsockopt, sock, level, optname, optval, optlen);
}
#ifdef CONFIG_USERSPACE
@ -2474,7 +2507,7 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,
int z_impl_zsock_setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen)
{
VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen);
return VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen);
}
#ifdef CONFIG_USERSPACE
@ -2548,7 +2581,7 @@ int zsock_getpeername_ctx(struct net_context *ctx, struct sockaddr *addr,
int z_impl_zsock_getpeername(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
VTABLE_CALL(getpeername, sock, addr, addrlen);
return VTABLE_CALL(getpeername, sock, addr, addrlen);
}
#ifdef CONFIG_USERSPACE
@ -2627,7 +2660,7 @@ int zsock_getsockname_ctx(struct net_context *ctx, struct sockaddr *addr,
int z_impl_zsock_getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
VTABLE_CALL(getsockname, sock, addr, addrlen);
return VTABLE_CALL(getsockname, sock, addr, addrlen);
}
#ifdef CONFIG_USERSPACE

View file

@ -78,4 +78,56 @@ struct socket_op_vtable {
size_t msghdr_non_empty_iov_count(const struct msghdr *msg);
#if defined(CONFIG_NET_SOCKETS_OBJ_CORE)
int sock_obj_core_alloc(int sock, struct net_socket_register *reg,
int family, int type, int proto);
int sock_obj_core_alloc_find(int sock, int new_sock, int family, int type);
int sock_obj_core_dealloc(int sock);
void sock_obj_core_update_send_stats(int sock, int bytes);
void sock_obj_core_update_recv_stats(int sock, int bytes);
#else
static inline int sock_obj_core_alloc(int sock,
struct net_socket_register *reg,
int family, int type, int proto)
{
ARG_UNUSED(sock);
ARG_UNUSED(reg);
ARG_UNUSED(family);
ARG_UNUSED(type);
ARG_UNUSED(proto);
return -ENOTSUP;
}
static inline int sock_obj_core_alloc_find(int sock, int new_sock,
int family, int type)
{
ARG_UNUSED(sock);
ARG_UNUSED(new_sock);
ARG_UNUSED(family);
ARG_UNUSED(type);
return -ENOTSUP;
}
static inline int sock_obj_core_dealloc(int sock)
{
ARG_UNUSED(sock);
return -ENOTSUP;
}
static inline void sock_obj_core_update_send_stats(int sock, int bytes)
{
ARG_UNUSED(sock);
ARG_UNUSED(bytes);
}
static inline void sock_obj_core_update_recv_stats(int sock, int bytes)
{
ARG_UNUSED(sock);
ARG_UNUSED(bytes);
}
#endif /* CONFIG_NET_SOCKETS_OBJ_CORE */
#endif /* _SOCKETS_INTERNAL_H_ */