diff --git a/configure.ac b/configure.ac index 8de6af616ff..fa58043bb7d 100644 --- a/configure.ac +++ b/configure.ac @@ -592,6 +592,10 @@ AC_CHECK_DECL([SO_PASSCRED], [#include #include ]) +AC_CHECK_DECLS([VMADDR_CID_LOCAL], [], [], [ + #include + #include ]) + AC_CHECK_FUNCS([ \ cachestat \ clearenv \ diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index 28f6abd5eb8..e3abb0690aa 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -275,6 +275,11 @@ Cooked version of KNAME. It is mostly same as KNAME. + Some files have special formats and information sources: + +AF_VSOCK::: +state=_SOCK.STATE_ type=_SOCK.TYPE_ laddr=_VSOCK.LADDR_[ raddr=_VSOCK.RADDR_] ++ +`raddr` is not shown for listening sockets. ++ bpf-map::: id=_BPF-MAP.ID_ type=_BPF-MAP.TYPE_[ name=_BPF.NAME_] + @@ -348,7 +353,6 @@ state=_SOCK.STATE_[ path=_UNIX.PATH_] + UNIX::: state=_SOCK.STATE_[ path=_UNIX.PATH_] type=_SOCK.TYPE_ - ____ Note that `(deleted)` markers are removed from this column. Refer to _KNAME_, _DELETED_, or _XMODE_ to know the @@ -546,6 +550,22 @@ Filesystem pathname for UNIX domain socket. USER <``string``>:: User of the process. +VSOCK.LADDR <``string``>:: +VSOCK.RADDR <``string``>:: +Local VSOCK address. The format of the element +is _VSOCK.LCID_``:``_VSOCK.LPORT_. ++ +Well-known CIDs will be decoded: "`{asterisk}`", "`hypervisor`", "`local`", or "`host`". +Well-known ports will be decoded: "`{asterisk}`". + +VSOCK.LCID <``number``>:: +VSOCK.RCID <``number``>:: +Local and remote VSOCK context identifiers. + +VSOCK.LPORT <``number``>:: +VSOCK.RPORT <``number``>:: +Local and remote VSOCK ports. + XMODE <``string``>:: Extended version of _MODE_. This column may grow; new letters may be appended to _XMODE_ when *lsfd* supports a new state of file descriptors @@ -729,7 +749,8 @@ mailto:kzak@redhat.com[Karel Zak] *scols-filter*(5), *socket*(2), *ss*(8), -*stat*(2) +*stat*(2), +*vsock*(7) include::man-common/bugreports.adoc[] diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 242dd4ef72d..77a7a0c22cc 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -431,6 +431,24 @@ static const struct colinfo infos[] = { [COL_USER] = { "USER", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("user of the process") }, + [COL_VSOCK_LCID] = { "VSOCK.LCID", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + N_("local VSOCK context identifier") }, + [COL_VSOCK_RCID] = { "VSOCK.RCID", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + N_("remote VSOCK context identifier") }, + [COL_VSOCK_LPORT] = { "VSOCK.LPORT", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + N_("local VSOCK port") }, + [COL_VSOCK_RPORT] = { "VSOCK.RPORT", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + N_("remote VSOCK port") }, + [COL_VSOCK_LADDR] = { "VSOCK.LADDR", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, + N_("local VSOCK address (CID:PORT)") }, + [COL_VSOCK_RADDR] = { "VSOCK.RADDR", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, + N_("remote VSOCK address (CID:PORT)") }, [COL_XMODE] = { "XMODE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("extended version of MODE (rwxD[Ll]m)") }, diff --git a/lsfd-cmd/lsfd.h b/lsfd-cmd/lsfd.h index 28eb69c1485..c9156757e11 100644 --- a/lsfd-cmd/lsfd.h +++ b/lsfd-cmd/lsfd.h @@ -142,6 +142,12 @@ enum { COL_UID, /* process */ COL_UNIX_PATH, COL_USER, /* process */ + COL_VSOCK_LADDR, + COL_VSOCK_RADDR, + COL_VSOCK_LCID, + COL_VSOCK_RCID, + COL_VSOCK_LPORT, + COL_VSOCK_RPORT, COL_XMODE, LSFD_N_COLS /* This must be at last. */ }; diff --git a/lsfd-cmd/sock-xinfo.c b/lsfd-cmd/sock-xinfo.c index 3bc45737d8d..f6811213aa4 100644 --- a/lsfd-cmd/sock-xinfo.c +++ b/lsfd-cmd/sock-xinfo.c @@ -33,6 +33,8 @@ #include /* UNIX_PATH_MAX */ #include /* UNIX_DIAG_*, UDIAG_SHOW_*, struct unix_diag_req */ +#include /* VMADDR_CID* */ +#include /* vsock_diag_req/vsock_diag_msg */ #include /* for setns(2) */ #include /* tfind, tsearch */ #include @@ -62,6 +64,7 @@ static void load_xinfo_from_proc_netlink(ino_t netns_inode); static void load_xinfo_from_proc_packet(ino_t netns_inode); static void load_xinfo_from_diag_unix(int diag, ino_t netns_inode); +static void load_xinfo_from_diag_vsock(int diag, ino_t netns_inode); static int self_netns_fd = -1; static struct stat self_netns_sb; @@ -186,6 +189,7 @@ static void load_sock_xinfo_no_nsswitch(struct netns *nsobj) (diagsd >= 0)? "successful": strerror(errno))); if (diagsd >= 0) { load_xinfo_from_diag_unix(diagsd, netns); + load_xinfo_from_diag_vsock(diagsd, netns); close(diagsd); DBG(ENDPOINTS, ul_debug("close the diagnose socket")); } @@ -2388,3 +2392,215 @@ static void load_xinfo_from_proc_packet(ino_t netns_inode) out: fclose(packet_fp); } + +/* + * VSOCK + */ +struct vsock_addr { + uint32_t cid; + uint32_t port; +}; + +struct vsock_xinfo { + struct sock_xinfo sock; + uint8_t type; + uint8_t st; + uint8_t shutdown_mask:3; + struct vsock_addr local; + struct vsock_addr remote; +}; + +static const char *vsock_decode_cid(uint32_t cid) +{ + switch (cid) { + case VMADDR_CID_ANY: + return "*"; + case VMADDR_CID_HYPERVISOR: + return "hypervisor"; +#if HAVE_DECL_VMADDR_CID_LOCAL + case VMADDR_CID_LOCAL: + return "local"; +#endif /* HAVE_DECL_VMADDR_CID_LOCAL */ + case VMADDR_CID_HOST: + return "host"; + default: + return NULL; + } +} + +static const char *vsock_decode_port(uint32_t port) +{ + if (port == VMADDR_PORT_ANY) + return "*"; + return NULL; +} + +static char* vsock_get_addr(struct vsock_addr *addr) +{ + const char *tmp_cid = vsock_decode_cid(addr->cid); + const char *tmp_port = vsock_decode_port(addr->port); + char cidstr[BUFSIZ]; + char portstr[BUFSIZ]; + char *str = NULL; + + if (tmp_cid) + snprintf(cidstr, sizeof(cidstr), "%s", tmp_cid); + else + snprintf(cidstr, sizeof(cidstr), "%"PRIu32, addr->cid); + + if (tmp_port) + snprintf(portstr, sizeof(portstr), "%s", tmp_port); + else + snprintf(portstr, sizeof(portstr), "%"PRIu32, addr->port); + + xasprintf(&str, "%s:%s", cidstr, portstr); + return str; +} + +static char *vsock_get_name(struct sock_xinfo *sock_xinfo, + struct sock *sock __attribute__((__unused__))) +{ + struct vsock_xinfo *vs = (struct vsock_xinfo *)sock_xinfo; + char *str = NULL; + const char *st_str = l4_decode_state(vs->st); + const char *type_str = sock_decode_type(vs->type); + char *laddr = vsock_get_addr(&vs->local); + + if (vs->st == TCP_LISTEN) + xasprintf(&str, "state=%s type=%s laddr=%s", + st_str, type_str, laddr); + else { + char *raddr = vsock_get_addr(&vs->remote); + + xasprintf(&str, "state=%s type=%s laddr=%s raddr=%s", + st_str, type_str, laddr, raddr); + free(raddr); + } + free(laddr); + + return str; +} + +static char *vsock_get_type(struct sock_xinfo *sock_xinfo, + struct sock *sock __attribute__((__unused__))) +{ + const char *str; + struct vsock_xinfo *vs = (struct vsock_xinfo *)sock_xinfo; + + str = sock_decode_type(vs->type); + return xstrdup(str); +} + +static char *vsock_get_state(struct sock_xinfo *sock_xinfo, + struct sock *sock __attribute__((__unused__))) +{ + const char *str; + struct vsock_xinfo *vs = (struct vsock_xinfo *)sock_xinfo; + + str = l4_decode_state(vs->st); + return xstrdup(str); +} + +static bool vsock_get_listening(struct sock_xinfo *sock_xinfo, + struct sock *sock __attribute__((__unused__))) +{ + return ((struct vsock_xinfo *)sock_xinfo)->st == TCP_LISTEN; +} + +static bool vsock_fill_column(struct proc *proc __attribute__((__unused__)), + struct sock_xinfo *sock_xinfo, + struct sock *sock __attribute__((__unused__)), + struct libscols_line *ln __attribute__((__unused__)), + int column_id, + size_t column_index __attribute__((__unused__)), + char **str) +{ + struct vsock_xinfo *vs = (struct vsock_xinfo *)sock_xinfo; + + switch (column_id) { + case COL_VSOCK_LCID: + xasprintf(str, "%"PRIu32, vs->local.cid); + return true; + case COL_VSOCK_RCID: + xasprintf(str, "%"PRIu32, vs->remote.cid); + return true; + case COL_VSOCK_LPORT: + xasprintf(str, "%"PRIu32, vs->local.port); + return true; + case COL_VSOCK_RPORT: + xasprintf(str, "%"PRIu32, vs->remote.port); + return true; + case COL_VSOCK_LADDR: + *str = vsock_get_addr(&vs->local); + return true; + case COL_VSOCK_RADDR: + *str = vsock_get_addr(&vs->remote); + return true; + } + return false; +} + +static const struct sock_xinfo_class vsock_xinfo_class = { + .get_name = vsock_get_name, + .get_type = vsock_get_type, + .get_state = vsock_get_state, + .get_listening = vsock_get_listening, + .fill_column = vsock_fill_column, + .free = NULL, +}; + +static bool handle_diag_vsock(ino_t netns __attribute__((__unused__)), + size_t nlmsg_len, void *nlmsg_data) +{ + const struct vsock_diag_msg *diag = nlmsg_data; + ino_t inode; + struct sock_xinfo *xinfo; + struct vsock_xinfo *vx; + + if (diag->vdiag_family != AF_VSOCK) + return false; + DBG(ENDPOINTS, ul_debug(" VSOCK")); + DBG(ENDPOINTS, ul_debug(" LEN: %zu (>= %zu)", nlmsg_len, + (size_t)(NLMSG_LENGTH(sizeof(*diag))))); + + if (nlmsg_len < NLMSG_LENGTH(sizeof(*diag))) + return false; + + inode = (ino_t)diag->vdiag_ino; + DBG(ENDPOINTS, ul_debug(" inode: %llu", (unsigned long long)inode)); + + xinfo = get_sock_xinfo(inode); + if (xinfo != NULL) + /* It seems that the same socket reported twice. */ + return true; + + vx = xcalloc(1, sizeof(*vx)); + xinfo = &vx->sock; + DBG(ENDPOINTS, ul_debug(" xinfo: %p", xinfo)); + + xinfo->class = &vsock_xinfo_class; + xinfo->inode = (ino_t)inode; + xinfo->netns_inode = (ino_t)netns; + + vx->type = diag->vdiag_type; + vx->st = diag->vdiag_state; + vx->shutdown_mask = diag->vdiag_shutdown; + vx->local.cid = diag->vdiag_src_cid; + vx->local.port = diag->vdiag_src_port; + vx->remote.cid = diag->vdiag_dst_cid; + vx->remote.port = diag->vdiag_dst_port; + + add_sock_info(xinfo); + return true; +} + +static void load_xinfo_from_diag_vsock(int diagsd, ino_t netns) +{ + struct vsock_diag_req vdr; + + memset(&vdr, 0, sizeof(vdr)); + vdr.sdiag_family = AF_VSOCK; + vdr.vdiag_states = ~(uint32_t)0; + + send_diag_request(diagsd, &vdr, sizeof(vdr), handle_diag_vsock, netns); +} diff --git a/meson.build b/meson.build index 949a0e41feb..462ceaae224 100644 --- a/meson.build +++ b/meson.build @@ -830,6 +830,10 @@ have_so_passcred = cc.has_header_symbol( prefix : '#include ', required : build_plymouth_support.enabled()) +have = cc.has_header_symbol('linux/vm_sockets.h', 'VMADDR_CID_LOCAL', + prefix : '#include ') +conf.set('HAVE_DECL_VMADDR_CID_LOCAL', have ? 1 : false) + build_plymouth_support = (not build_plymouth_support.disabled() and have_tiocglcktrmios and have_sock_cloexec and diff --git a/tests/expected/lsfd/mkfds-vsock b/tests/expected/lsfd/mkfds-vsock new file mode 100644 index 00000000000..2fa9de90b4c --- /dev/null +++ b/tests/expected/lsfd/mkfds-vsock @@ -0,0 +1,25 @@ +# TYPE: STREAM +3 SOCK state=listen type=stream laddr=local:12345 listen stream 1 +4 SOCK state=established type=stream laddr=local:23456 raddr=local:12345 established stream 0 +5 SOCK state=established type=stream laddr=local:12345 raddr=local:23456 established stream 0 +ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING: 0 +local:12345 1 12345 *:* 4294967295 4294967295 +local:23456 1 23456 local:12345 1 12345 +local:12345 1 12345 local:23456 1 23456 +VSOCK.LADDR,VSOCK.LCID,VSOCK.LPORT,VSOCK.RADDR,VSOCK.RCID,VSOCK.RPORT: 0 +# TYPE: DGRAM +3 SOCK state=established type=dgram laddr=local:12345 raddr=local:23456 established dgram 0 +4 SOCK state=established type=dgram laddr=local:23456 raddr=local:12345 established dgram 0 +ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING: 0 +local:12345 1 12345 local:23456 1 23456 +local:23456 1 23456 local:12345 1 12345 +VSOCK.LADDR,VSOCK.LCID,VSOCK.LPORT,VSOCK.RADDR,VSOCK.RCID,VSOCK.RPORT: 0 +# TYPE: SEQPACKET +3 SOCK state=listen type=seqpacket laddr=local:12345 listen seqpacket 1 +4 SOCK state=established type=seqpacket laddr=local:23456 raddr=local:12345 established seqpacket 0 +5 SOCK state=established type=seqpacket laddr=local:12345 raddr=local:23456 established seqpacket 0 +ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING: 0 +local:12345 1 12345 *:* 4294967295 4294967295 +local:23456 1 23456 local:12345 1 12345 +local:12345 1 12345 local:23456 1 23456 +VSOCK.LADDR,VSOCK.LCID,VSOCK.LPORT,VSOCK.RADDR,VSOCK.RCID,VSOCK.RPORT: 0 diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index 5709b2bce11..dfb60ae8ece 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -37,6 +37,7 @@ #include # include /* for UNIX domain sockets */ #include /* SIOCGSKNS */ +#include #include #include #include @@ -74,6 +75,8 @@ #define EXIT_EACCES 21 #define EXIT_ENOENT 22 #define EXIT_ENOSYS 23 +#define EXIT_EADDRNOTAVAIL 24 +#define EXIT_ENODEV 25 #define _U_ __attribute__((__unused__)) @@ -2016,6 +2019,145 @@ static void *make_ping6(const struct factory *factory, struct fdesc fdescs[], (struct sockaddr *)&in6); } +#if HAVE_DECL_VMADDR_CID_LOCAL +static void *make_vsock(const struct factory *factory, struct fdesc fdescs[], + int argc, char ** argv) +{ + struct sockaddr_vm svm; + struct sockaddr_vm cvm; + + struct arg server_port = decode_arg("server-port", factory->params, argc, argv); + unsigned short iserver_port = (unsigned short)ARG_INTEGER(server_port); + struct arg client_port = decode_arg("client-port", factory->params, argc, argv); + unsigned short iclient_port = (unsigned short)ARG_INTEGER(client_port); + struct arg socktype = decode_arg("socktype", factory->params, argc, argv); + int isocktype; + int ssd, csd, asd = -1; + + const int y = 1; + + free_arg(&server_port); + free_arg(&client_port); + + if (strcmp(ARG_STRING(socktype), "STREAM") == 0) + isocktype = SOCK_STREAM; + else if (strcmp(ARG_STRING(socktype), "DGRAM") == 0) + isocktype = SOCK_DGRAM; + else if (strcmp(ARG_STRING(socktype), "SEQPACKET") == 0) + isocktype = SOCK_SEQPACKET; + else + errx(EXIT_FAILURE, + "unknown socket type for socket(AF_VSOCK,...): %s", + ARG_STRING(socktype)); + free_arg(&socktype); + + ssd = socket(AF_VSOCK, isocktype, 0); + if (ssd < 0) { + if (errno == ENODEV) + err(EXIT_ENODEV, "failed to make a vsock socket for listening (maybe `modprobe vmw_vsock_vmci_transport'?)"); + err(EXIT_FAILURE, + "failed to make a vsock socket for listening"); + } + + if (setsockopt(ssd, SOL_SOCKET, + SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) { + err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)"); + } + + if (ssd != fdescs[0].fd) { + if (dup2(ssd, fdescs[0].fd) < 0) { + err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd); + } + close(ssd); + ssd = fdescs[0].fd; + } + + memset(&svm, 0, sizeof(svm)); + svm.svm_family = AF_VSOCK; + svm.svm_port = iserver_port; + svm.svm_cid = VMADDR_CID_LOCAL; + + memset(&cvm, 0, sizeof(svm)); + cvm.svm_family = AF_VSOCK; + cvm.svm_port = iclient_port; + cvm.svm_cid = VMADDR_CID_LOCAL; + + if (bind(ssd, (struct sockaddr *)&svm, sizeof(svm)) < 0) { + if (errno == EADDRNOTAVAIL) + err(EXIT_EADDRNOTAVAIL, "failed to bind a listening socket (maybe `modprobe vsock_loopback'?)"); + err(EXIT_FAILURE, "failed to bind a listening socket"); + } + + + if (isocktype == SOCK_DGRAM) { + if (connect(ssd, (struct sockaddr *)&cvm, sizeof(cvm)) < 0) + err(EXIT_FAILURE, "failed to connect the server socket to a client socket"); + } else { + if (listen(ssd, 1) < 0) + err(EXIT_FAILURE, "failed to listen a socket"); + } + + csd = socket(AF_VSOCK, isocktype, 0); + if (csd < 0) { + err(EXIT_FAILURE, + "failed to make a vsock client socket"); + } + + if (setsockopt(csd, SOL_SOCKET, + SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) { + err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)"); + } + + if (csd != fdescs[1].fd) { + if (dup2(csd, fdescs[1].fd) < 0) { + err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd); + } + close(csd); + csd = fdescs[1].fd; + } + + if (bind(csd, (struct sockaddr *)&cvm, sizeof(cvm)) < 0) { + err(EXIT_FAILURE, "failed to bind a client socket"); + } + + if (connect(csd, (struct sockaddr *)&svm, sizeof(svm)) < 0) { + err(EXIT_FAILURE, "failed to connect a client socket to the server socket"); + } + + if (isocktype != SOCK_DGRAM) { + asd = accept(ssd, NULL, NULL); + if (asd < 0) { + err(EXIT_FAILURE, "failed to accept a socket from the listening socket"); + } + if (asd != fdescs[2].fd) { + if (dup2(asd, fdescs[2].fd) < 0) { + err(EXIT_FAILURE, "failed to dup %d -> %d", asd, fdescs[2].fd); + } + close(asd); + asd = fdescs[2].fd; + } + } + + fdescs[0] = (struct fdesc) { + .fd = fdescs[0].fd, + .close = close_fdesc, + .data = NULL, + }; + fdescs[1] = (struct fdesc) { + .fd = fdescs[1].fd, + .close = close_fdesc, + .data = NULL, + }; + + fdescs[2] = (struct fdesc) { + .fd = (iserver_port == SOCK_DGRAM)? -1: fdescs[2].fd, + .close = close_fdesc, + .data = NULL, + }; + return NULL; +} +#endif /* HAVE_DECL_VMADDR_CID_LOCAL */ + #ifdef SIOCGSKNS static void *make_netns(const struct factory *factory _U_, struct fdesc fdescs[], int argc _U_, char ** argv _U_) @@ -3810,6 +3952,37 @@ static const struct factory factories[] = { PARAM_END } }, +#if HAVE_DECL_VMADDR_CID_LOCAL + { + "vsock", + .desc = "AF_VSOCK sockets", + .priv = false, + .N = 3, /* NOTE: The 3rd one is not used if socktype is DGRAM. */ + .EX_N = 0, + .make = make_vsock, + .params = (struct parameter []) { + { + .name = "socktype", + .type = PTYPE_STRING, + .desc = "STREAM, DGRAM, or SEQPACKET", + .defv.string = "STREAM", + }, + { + .name = "server-port", + .type = PTYPE_INTEGER, + .desc = "VSOCK port the server may listen", + .defv.integer = 12345, + }, + { + .name = "client-port", + .type = PTYPE_INTEGER, + .desc = "VSOCK port the client may bind", + .defv.integer = 23456, + }, + PARAM_END + } + }, +#endif /* HAVE_DECL_VMADDR_CID_LOCAL */ #ifdef SIOCGSKNS { .name = "netns", diff --git a/tests/ts/lsfd/lsfd-functions.bash b/tests/ts/lsfd/lsfd-functions.bash index dda315d95f1..1b2a0ac042b 100644 --- a/tests/ts/lsfd/lsfd-functions.bash +++ b/tests/ts/lsfd/lsfd-functions.bash @@ -22,6 +22,8 @@ readonly EPROTONOSUPPORT=20 readonly EACCES=21 readonly ENOENT=22 readonly ENOSYS=23 +readonly EADDRNOTAVAIL=24 +readonly ENODEV=25 function lsfd_wait_for_pausing { ts_check_prog "sleep" @@ -125,3 +127,25 @@ function lsfd_check_sockdiag ts_failed "failed to create a sockdiag netlink socket $family ($err): $msg";; esac } + +function lsfd_check_vsock +{ + ts_check_test_command "$TS_HELPER_MKFDS" + + local msg + local err + + msg=$("$TS_HELPER_MKFDS" -c vsock 3 4 5 socktype=DGRAM 2>&1) + err=$? + + case $err in + 0) + return;; + "$EADDRNOTAVAIL") + ts_skip "VMADDR_CID_LOCAL doesn't work";; + "$ENODEV") + ts_skip "AF_VSOCK+SOCK_DGRAM doesn't work";; + *) + ts_failed "failed to use a AF_VSOCK socket: $msg [$err]";; + esac +} diff --git a/tests/ts/lsfd/mkfds-vsock b/tests/ts/lsfd/mkfds-vsock new file mode 100755 index 00000000000..7b740aca06b --- /dev/null +++ b/tests/ts/lsfd/mkfds-vsock @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Copyright (C) 2024 Masatake YAMATO +# +# This file is part of util-linux. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +TS_TOPDIR="${0%/*}/../.." +TS_DESC="VSOCK stream sockets" + +. "$TS_TOPDIR"/functions.sh +ts_init "$*" +ts_skip_nonroot + +. "$TS_SELF/lsfd-functions.bash" + +ts_check_test_command "$TS_CMD_LSFD" +ts_check_test_command "$TS_HELPER_MKFDS" + +lsfd_check_mkfds_factory vsock + +ts_check_prog "modprobe" + +ts_cd "$TS_OUTDIR" + +PID= +FDS=3 +FDC=4 +FDA=5 +SPORT=12345 +CPORT=23456 +EXPR='(TYPE == "AF_VSOCK") and (FD >= 3) and (FD <= 5)' + +# AF_VSOCK+SOCK_DGRAM requires this. +modprobe --quiet vmw_vsock_vmci_transport ||: +modprobe --quiet vmw_vsock_virtio_transport ||: +modprobe --quiet hv_vsock ||: + +# VMADDR_CID_LOCAL requires this. +modprobe --quiet vsock_loopback ||: + +lsfd_check_vsock + +{ + + for t in STREAM DGRAM SEQPACKET; do + coproc MKFDS { "$TS_HELPER_MKFDS" vsock $FDS $FDC $FDA \ + server-port=$SPORT client-port=$CPORT \ + socktype=$t ; } + if read -r -u "${MKFDS[0]}" PID; then + echo "# TYPE: $t" + ${TS_CMD_LSFD} -n \ + -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING \ + -p "${PID}" -Q "${EXPR}" + echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING': ${PIPESTATUS[0]} + ${TS_CMD_LSFD} -n \ + -o VSOCK.LADDR,VSOCK.LCID,VSOCK.LPORT,VSOCK.RADDR,VSOCK.RCID,VSOCK.RPORT \ + -p "${PID}" -Q "${EXPR}" + echo 'VSOCK.LADDR,VSOCK.LCID,VSOCK.LPORT,VSOCK.RADDR,VSOCK.RCID,VSOCK.RPORT': ${PIPESTATUS[0]} + echo DONE >&"${MKFDS[1]}" + fi + wait "${MKFDS_PID}" + done +} > "$TS_OUTPUT" 2>&1 + +ts_finalize