[#include <sys/types.h>
#include <sys/socket.h>])
+AC_CHECK_DECLS([VMADDR_CID_LOCAL], [], [], [
+ #include <sys/socket.h>
+ #include <linux/vm_sockets.h>])
+
AC_CHECK_FUNCS([ \
cachestat \
clearenv \
+
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_]
+
+
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
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
*scols-filter*(5),
*socket*(2),
*ss*(8),
-*stat*(2)
+*stat*(2),
+*vsock*(7)
include::man-common/bugreports.adoc[]
[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)") },
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. */
};
#include <linux/un.h> /* UNIX_PATH_MAX */
#include <linux/unix_diag.h> /* UNIX_DIAG_*, UDIAG_SHOW_*,
struct unix_diag_req */
+#include <linux/vm_sockets.h> /* VMADDR_CID* */
+#include <linux/vm_sockets_diag.h> /* vsock_diag_req/vsock_diag_msg */
#include <sched.h> /* for setns(2) */
#include <search.h> /* tfind, tsearch */
#include <stdint.h>
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;
(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"));
}
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);
+}
prefix : '#include <sys/types.h>',
required : build_plymouth_support.enabled())
+have = cc.has_header_symbol('linux/vm_sockets.h', 'VMADDR_CID_LOCAL',
+ prefix : '#include <sys/socket.h>')
+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
--- /dev/null
+# 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
#include <linux/sock_diag.h>
# include <linux/unix_diag.h> /* for UNIX domain sockets */
#include <linux/sockios.h> /* SIOCGSKNS */
+#include <linux/vm_sockets.h>
#include <mqueue.h>
#include <net/if.h>
#include <netinet/in.h>
#define EXIT_EACCES 21
#define EXIT_ENOENT 22
#define EXIT_ENOSYS 23
+#define EXIT_EADDRNOTAVAIL 24
+#define EXIT_ENODEV 25
#define _U_ __attribute__((__unused__))
(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_)
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",
readonly EACCES=21
readonly ENOENT=22
readonly ENOSYS=23
+readonly EADDRNOTAVAIL=24
+readonly ENODEV=25
function lsfd_wait_for_pausing {
ts_check_prog "sleep"
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
+}
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2024 Masatake YAMATO <yamato@redhat.com>
+#
+# 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