git: 8b2b62b49d88 - main - sockstat: consolidate unix(4) protocols in the array of protocols
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 16 Jun 2026 17:03:26 UTC
The branch main has been updated by glebius:
URL: https://cgit.FreeBSD.org/src/commit/?id=8b2b62b49d886816213fb6b39258afb1373ef43b
commit 8b2b62b49d886816213fb6b39258afb1373ef43b
Author: Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-06-16 16:59:01 +0000
Commit: Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-06-16 16:59:01 +0000
sockstat: consolidate unix(4) protocols in the array of protocols
This makes it possible to list unix(4) protocols in -P, which was not
possible before. Update the manual page and provide an example.
In 'struct sock' make member proto a pointer into the protocols table
instead of a number. This removes namespace collision that mixed
IPPROTO_TCP and etc with SOCK_STREAM and etc. There were no known bugs
due to this collision, though.
Preserve all current UI bugs for possible combinations of protocol
selection options. Should be no UI changes outside the improved -P.
Reviewed by: pouria, tuexen
Differential Revision: https://reviews.freebsd.org/D57508
---
usr.bin/sockstat/main.c | 214 ++++++++++++++++++++++----------------------
usr.bin/sockstat/sockstat.1 | 12 ++-
2 files changed, 120 insertions(+), 106 deletions(-)
diff --git a/usr.bin/sockstat/main.c b/usr.bin/sockstat/main.c
index aa7d8f3d378c..0edf8dcbd431 100644
--- a/usr.bin/sockstat/main.c
+++ b/usr.bin/sockstat/main.c
@@ -107,49 +107,59 @@ static bool show_path_state = false;
/*
* Protocols that we support.
- * TODO: merge unix(4) protocols into here.
*/
+enum sockstatproto {
+ SCTP = 0, TCP, UDP, UDPLITE, DIVERT, STREAM, DGRAM, SEQPACK
+};
struct proto;
typedef void gather_func_t(struct proto *);
-static gather_func_t gather_sctp, gather_inet;
+static gather_func_t gather_sctp, gather_inet, gather_unix;
static struct proto {
gather_func_t *gather;
const char *name;
const char *pcblist;
- union {
- int protonum; /* gather_inet() */
- };
bool disabled;
} protos[] = {
- {
+ [SCTP] = {
.name = "sctp",
.gather = gather_sctp,
.pcblist = "net.inet.sctp.assoclist",
- .protonum = IPPROTO_SCTP,
},
- {
+ [TCP] = {
.name = "tcp",
.gather = gather_inet,
.pcblist = "net.inet.tcp.pcblist",
- .protonum = IPPROTO_TCP,
},
- {
+ [UDP] = {
.name = "udp",
.gather = gather_inet,
.pcblist = "net.inet.udp.pcblist",
- .protonum = IPPROTO_UDP,
},
- {
+ [UDPLITE] = {
.name = "udplite",
.gather = gather_inet,
.pcblist = "net.inet.udplite.pcblist",
- .protonum = IPPROTO_UDPLITE,
},
- {
+ [DIVERT] = {
.name = "divert",
.gather = gather_inet,
.pcblist = "net.inet.divert.pcblist",
},
+ [STREAM] = {
+ .name = "unix/stream",
+ .gather = gather_unix,
+ .pcblist = "net.local.stream.pcblist",
+ },
+ [DGRAM] = {
+ .name = "unix/dgram",
+ .gather = gather_unix,
+ .pcblist = "net.local.dgram.pcblist",
+ },
+ [SEQPACK] = {
+ .name = "unix/seqpack",
+ .gather = gather_unix,
+ .pcblist = "net.local.seqpacket.pcblist",
+ },
};
/*
@@ -185,10 +195,10 @@ struct sock {
int shown;
int vflag;
int family;
- int proto;
int state;
int fibnum;
int bblog_state;
+ const struct proto *proto;
const char *protoname;
char stack[TCP_FUNCTION_NAME_LEN_MAX];
char cc[TCP_CA_NAME_MAX];
@@ -387,8 +397,7 @@ gather_sctp(struct proto *proto)
if ((sock = calloc(1, sizeof *sock)) == NULL)
xo_err(1, "malloc()");
sock->socket = xinpcb->socket;
- sock->proto = IPPROTO_SCTP;
- sock->protoname = "sctp";
+ sock->proto = proto;
if (xinpcb->maxqlen == 0)
sock->state = SCTP_CLOSED;
else
@@ -488,8 +497,7 @@ gather_sctp(struct proto *proto)
if ((sock = calloc(1, sizeof *sock)) == NULL)
xo_err(1, "malloc()");
sock->socket = xinpcb->socket;
- sock->proto = IPPROTO_SCTP;
- sock->protoname = "sctp";
+ sock->proto = proto;
sock->state = (int)xstcb->state;
if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) {
sock->family = AF_INET6;
@@ -665,7 +673,7 @@ gather_inet(struct proto *proto)
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
if (xig >= exig)
break;
- if (proto->protonum == IPPROTO_TCP) {
+ if (proto == &protos[TCP]) {
xtp = (struct xtcpcb *)xig;
xip = &xtp->xt_inp;
if (!check_ksize(xtp->xt_len, struct xtcpcb))
@@ -713,7 +721,7 @@ gather_inet(struct proto *proto)
sock->socket = so->xso_so;
sock->pcb = so->so_pcb;
sock->splice_socket = so->so_splice_so;
- sock->proto = proto->protonum;
+ sock->proto = proto;
sock->inp_gencnt = xip->inp_gencnt;
sock->fibnum = so->so_fibnum;
if (xip->inp_vflag & INP_IPV4) {
@@ -729,14 +737,14 @@ gather_inet(struct proto *proto)
sockaddr(&faddr->address, sock->family,
&xip->in6p_faddr, xip->inp_fport);
}
- if (proto->protonum == IPPROTO_TCP)
+ if (proto == &protos[TCP])
faddr->encaps_port = xtp->xt_encaps_port;
laddr->next = NULL;
faddr->next = NULL;
sock->laddr = laddr;
sock->faddr = faddr;
sock->vflag = xip->inp_vflag;
- if (proto->protonum == IPPROTO_TCP) {
+ if (proto == &protos[TCP]) {
sock->state = xtp->t_state;
sock->bblog_state = xtp->t_logstate;
memcpy(sock->stack, xtp->xt_stack,
@@ -755,33 +763,22 @@ out:
}
static void
-gather_unix(int proto)
+gather_unix(struct proto *proto)
{
struct xunpgen *xug, *exug;
struct xunpcb *xup;
struct sock *sock;
struct addr *laddr, *faddr;
- const char *varname, *protoname;
+ const char *protoname;
size_t len, bufsize;
void *buf;
int retry;
- switch (proto) {
- case SOCK_STREAM:
- varname = "net.local.stream.pcblist";
- protoname = "stream";
- break;
- case SOCK_DGRAM:
- varname = "net.local.dgram.pcblist";
- protoname = "dgram";
- break;
- case SOCK_SEQPACKET:
- varname = "net.local.seqpacket.pcblist";
- protoname = is_xo_style_encoding ? "seqpacket" : "seqpack";
- break;
- default:
- abort();
- }
+ if (proto == &protos[SEQPACK] && is_xo_style_encoding)
+ protoname = "seqpacket";
+ else
+ protoname = strchr(proto->name, '/') + 1;
+
buf = NULL;
bufsize = 8192;
retry = 5;
@@ -790,8 +787,8 @@ gather_unix(int proto)
if ((buf = realloc(buf, bufsize)) == NULL)
xo_err(1, "realloc()");
len = bufsize;
- if (cap_sysctlbyname(capsysctl, varname, buf, &len,
- NULL, 0) == 0)
+ if (cap_sysctlbyname(capsysctl, proto->pcblist, buf,
+ &len, NULL, 0) == 0)
break;
if (errno != ENOMEM || len != bufsize)
xo_err(1, "cap_sysctlbyname()");
@@ -1256,8 +1253,8 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
}
}
if (opt_i) {
- if (s->proto == IPPROTO_TCP ||
- s->proto == IPPROTO_UDP) {
+ if (s->proto == &protos[TCP] ||
+ s->proto == &protos[UDP]) {
len = snprintf(NULL, 0,
"%" PRIu64, s->inp_gencnt);
cw->inp_gencnt = MAX(cw->inp_gencnt, len);
@@ -1265,11 +1262,11 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
}
if (opt_U) {
if (faddr != NULL &&
- ((s->proto == IPPROTO_SCTP &&
+ ((s->proto == &protos[SCTP] &&
s->state != SCTP_CLOSED &&
s->state != SCTP_BOUND &&
s->state != SCTP_LISTEN) ||
- (s->proto == IPPROTO_TCP &&
+ (s->proto == &protos[TCP] &&
s->state != TCPS_CLOSED &&
s->state != TCPS_LISTEN))) {
len = snprintf(NULL, 0, "%u",
@@ -1279,7 +1276,7 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
}
if (opt_s) {
if (faddr != NULL &&
- s->proto == IPPROTO_SCTP &&
+ s->proto == &protos[SCTP] &&
s->state != SCTP_CLOSED &&
s->state != SCTP_BOUND &&
s->state != SCTP_LISTEN) {
@@ -1289,33 +1286,27 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
}
if (first) {
if (opt_s) {
- if (s->proto == IPPROTO_SCTP ||
- s->proto == IPPROTO_TCP) {
- switch (s->proto) {
- case IPPROTO_SCTP:
+ if (s->proto == &protos[SCTP]) {
+ len = strlen(sctp_conn_state(s->state));
+ cw->conn_state = MAX(cw->conn_state,
+ len);
+ }
+ if (s->proto == &protos[TCP]) {
+ if (s->state >= 0 &&
+ s->state < TCP_NSTATES) {
len = strlen(
- sctp_conn_state(s->state));
+ tcpstates[s->state]);
cw->conn_state = MAX(
- cw->conn_state, len);
- break;
- case IPPROTO_TCP:
- if (s->state >= 0 &&
- s->state < TCP_NSTATES) {
- len = strlen(
- tcpstates[s->state]);
- cw->conn_state = MAX(
- cw->conn_state,
- len);
- }
- break;
+ cw->conn_state,
+ len);
}
}
}
- if (opt_S && s->proto == IPPROTO_TCP) {
+ if (opt_S && s->proto == &protos[TCP]) {
len = strlen(s->stack);
cw->stack = MAX(cw->stack, len);
}
- if (opt_C && s->proto == IPPROTO_TCP) {
+ if (opt_C && s->proto == &protos[TCP]) {
len = strlen(s->cc);
cw->cc = MAX(cw->cc, len);
}
@@ -1482,8 +1473,8 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
cw->splice_address, buf);
}
if (opt_i) {
- if (s->proto == IPPROTO_TCP ||
- s->proto == IPPROTO_UDP) {
+ if (s->proto == &protos[TCP] ||
+ s->proto == &protos[UDP]) {
snprintf(buf, bufsize, "%" PRIu64,
s->inp_gencnt);
xo_emit(" {:id/%*s}", cw->inp_gencnt, buf);
@@ -1492,11 +1483,11 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
}
if (opt_U) {
if (faddr != NULL &&
- ((s->proto == IPPROTO_SCTP &&
+ ((s->proto == &protos[SCTP] &&
s->state != SCTP_CLOSED &&
s->state != SCTP_BOUND &&
s->state != SCTP_LISTEN) ||
- (s->proto == IPPROTO_TCP &&
+ (s->proto == &protos[TCP] &&
s->state != TCPS_CLOSED &&
s->state != TCPS_LISTEN))) {
xo_emit(" {:encaps/%*u}", cw->encaps,
@@ -1506,7 +1497,7 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
}
if (opt_s && show_path_state) {
if (faddr != NULL &&
- s->proto == IPPROTO_SCTP &&
+ s->proto == &protos[SCTP] &&
s->state != SCTP_CLOSED &&
s->state != SCTP_BOUND &&
s->state != SCTP_LISTEN) {
@@ -1518,31 +1509,25 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
}
if (first) {
if (opt_s) {
- if (s->proto == IPPROTO_SCTP ||
- s->proto == IPPROTO_TCP) {
- switch (s->proto) {
- case IPPROTO_SCTP:
+ if (s->proto == &protos[SCTP]) {
+ xo_emit(" {:conn-state/%-*s}",
+ cw->conn_state,
+ sctp_conn_state(s->state));
+ } else if (s->proto == &protos[TCP]) {
+ if (s->state >= 0 &&
+ s->state < TCP_NSTATES)
xo_emit(" {:conn-state/%-*s}",
cw->conn_state,
- sctp_conn_state(s->state));
- break;
- case IPPROTO_TCP:
- if (s->state >= 0 &&
- s->state < TCP_NSTATES)
- xo_emit(" {:conn-state/%-*s}",
- cw->conn_state,
- tcpstates[s->state]);
- else if (!is_xo_style_encoding)
- xo_emit(" {:conn-state/%-*s}",
- cw->conn_state, "??");
- break;
- }
+ tcpstates[s->state]);
+ else if (!is_xo_style_encoding)
+ xo_emit(" {:conn-state/%-*s}",
+ cw->conn_state, "??");
} else if (!is_xo_style_encoding)
xo_emit(" {:conn-state/%-*s}",
cw->conn_state, "??");
}
if (opt_b) {
- if (s->proto == IPPROTO_TCP)
+ if (s->proto == &protos[TCP])
xo_emit(" {:bblog-state/%-*s}",
cw->bblog_state,
bblog_state(s->bblog_state));
@@ -1551,7 +1536,7 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
cw->bblog_state, "??");
}
if (opt_S) {
- if (s->proto == IPPROTO_TCP)
+ if (s->proto == &protos[TCP])
xo_emit(" {:stack/%-*s}",
cw->stack, s->stack);
else if (!is_xo_style_encoding)
@@ -1559,7 +1544,7 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
cw->stack, "??");
}
if (opt_C) {
- if (s->proto == IPPROTO_TCP)
+ if (s->proto == &protos[TCP])
xo_emit(" {:cc/%-*s}", cw->cc, s->cc);
else if (!is_xo_style_encoding)
xo_emit(" {:cc/%-*s}", cw->cc, "??");
@@ -1983,23 +1968,42 @@ main(int argc, char *argv[])
if (opt_F && !parse_filter_user())
xo_errx(1, "Invalid username or UID specified");
- if ((!opt_4 && !opt_6) && protos_defined)
- opt_4 = opt_6 = true;
- if (!opt_4 && !opt_6 && !opt_u)
- opt_4 = opt_6 = opt_u = true;
if (!opt_c && !opt_l)
opt_c = opt_l = true;
- if (opt_4 || opt_6)
- for (u_int i = 0; i < nitems(protos); i++)
- if (!protos[i].disabled)
- protos[i].gather(&protos[i]);
-
- if (opt_u || (!protos_defined && !opt_4 && !opt_6)) {
- gather_unix(SOCK_STREAM);
- gather_unix(SOCK_DGRAM);
- gather_unix(SOCK_SEQPACKET);
+ /*
+ * By default all protocols are gathered.
+ *
+ * With -u and without -[46] disables all but unix(4).
+ * With -[46] and without -u disables unix(4).
+ * With -P only specified are gathered and -4 and -6 are ignored,
+ * however -u is not ignored (historical bug).
+ *
+ * divert(4) is controlled by -4 (historical bug).
+ *
+ * NB: opt_4 and opt_6 are used outside this function, thus need to
+ * be set to true if both are false.
+ */
+ if (protos_defined) {
+ if (opt_u)
+ protos[STREAM].disabled = protos[DGRAM].disabled =
+ protos[SEQPACK].disabled = false;
+ } else {
+ if (!opt_u && (opt_4 || opt_6))
+ protos[STREAM].disabled = protos[DGRAM].disabled =
+ protos[SEQPACK].disabled = true;
+ if (opt_u && !(opt_4 || opt_6))
+ protos[SCTP].disabled = protos[TCP].disabled =
+ protos[UDP].disabled = protos[UDPLITE].disabled =
+ true;
}
+ if (!opt_4 && !opt_6)
+ opt_4 = opt_6 = true;
+
+ for (u_int i = 0; i < nitems(protos); i++)
+ if (!protos[i].disabled)
+ protos[i].gather(&protos[i]);
+
getfiles();
display();
exit(0);
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index 385b1c4952dc..b8fb420bb105 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -119,7 +119,10 @@ Recognized protocols are
.Qq tcp ,
.Qq sctp ,
.Qq udp ,
-.Qq udplite
+.Qq udplite ,
+.Qq unix/stream ,
+.Qq unix/dgram ,
+.Qq unix/seqpack ,
and
.Qq divert .
.It Fl q
@@ -257,6 +260,13 @@ Show TCP IPv6 sockets which are listening and connected (default):
$ sockstat -6 -P tcp
.Ed
.Pp
+Show all listening
+.Xr unix 4
+datagram sockets:
+.Bd -literal -offset indent
+$ sockstat -P unix/dgram -l
+.Ed
+.Pp
Show all sockets in JSON format with neat alignment:
.Bd -literal -offset indent
$ sockstat --libxo json,pretty