* [RFC iproute2-next] ss: remove /proc fallback paths
@ 2026-09-01 14:38 Stephen Hemminger
2026-10-18 20:07 ` Gopal Malaviya
0 siblings, 1 reply; 2+ messages in thread
From: Stephen Hemminger @ 2026-09-01 14:38 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger
This patch removes the old /proc/net fallback code in ss command.
The sock_diag netlink interfaces were all in 3.10, over 13 years ago.
No longer need to carry all the additional text parsing code.
Having less code also reduces the potential for AI scavenging of bugs.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
man/man8/ss.8 | 2 +-
misc/ss.c | 568 ++------------------------------------------------
2 files changed, 18 insertions(+), 552 deletions(-)
diff --git a/man/man8/ss.8 b/man/man8/ss.8
index 3871612d..0e934c40 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -317,7 +317,7 @@ closing. It supports IPv4 and IPv6 sockets only.
.B \-s, \-\-summary
Print summary statistics. This option does not parse socket lists obtaining
summary from various sources. It is useful when amount of sockets is so huge
-that parsing /proc/net/tcp is painful.
+that dumping the full socket list is painful.
.TP
.B \-E, \-\-events
Continually display sockets as they are destroyed
diff --git a/misc/ss.c b/misc/ss.c
index 26520cee..708b5cf7 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -473,17 +473,6 @@ static void filter_merge_defaults(struct filter *f)
}
}
-#define net_tcp_open() generic_proc_open("PROC_NET_TCP", "net/tcp")
-#define net_tcp6_open() generic_proc_open("PROC_NET_TCP6", "net/tcp6")
-#define net_udp_open() generic_proc_open("PROC_NET_UDP", "net/udp")
-#define net_udp6_open() generic_proc_open("PROC_NET_UDP6", "net/udp6")
-#define net_raw_open() generic_proc_open("PROC_NET_RAW", "net/raw")
-#define net_raw6_open() generic_proc_open("PROC_NET_RAW6", "net/raw6")
-#define net_unix_open() generic_proc_open("PROC_NET_UNIX", "net/unix")
-#define net_packet_open() generic_proc_open("PROC_NET_PACKET", \
- "net/packet")
-#define net_netlink_open() generic_proc_open("PROC_NET_NETLINK", \
- "net/netlink")
#define net_sockstat_open() generic_proc_open("PROC_NET_SOCKSTAT", \
"net/sockstat")
#define net_sockstat6_open() generic_proc_open("PROC_NET_SOCKSTAT6", \
@@ -809,7 +798,6 @@ struct sockstat {
int rq, wq;
unsigned int ino;
unsigned int uid;
- int refcnt;
unsigned int iface;
unsigned long long sk;
char *name;
@@ -2481,55 +2469,6 @@ static void inet_stats_print(struct sockstat *s, bool v6only)
proc_ctx_print(s);
}
-static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
- sockstat * s)
-{
- s->local.family = s->remote.family = family;
- if (family == AF_INET) {
- sscanf(loc, "%x:%lx", s->local.data, (unsigned long *)&s->lport);
- sscanf(rem, "%x:%lx", s->remote.data, (unsigned long *)&s->rport);
- s->local.bytelen = s->remote.bytelen = 4;
- return 0;
- } else {
- sscanf(loc, "%08x%08x%08x%08x:%lx",
- s->local.data,
- s->local.data + 1,
- s->local.data + 2,
- s->local.data + 3,
- (unsigned long *)&s->lport);
- sscanf(rem, "%08x%08x%08x%08x:%lx",
- s->remote.data,
- s->remote.data + 1,
- s->remote.data + 2,
- s->remote.data + 3,
- (unsigned long *)&s->rport);
- s->local.bytelen = s->remote.bytelen = 16;
- return 0;
- }
- return -1;
-}
-
-static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
-{
- char *p;
-
- if ((p = strchr(line, ':')) == NULL)
- return -1;
-
- *loc = p+2;
- if ((p = strchr(*loc, ':')) == NULL)
- return -1;
-
- p[5] = 0;
- *rem = p+6;
- if ((p = strchr(*rem, ':')) == NULL)
- return -1;
-
- p[5] = 0;
- *data = p+6;
- return 0;
-}
-
/*
* Display bandwidth in standard units
* See: https://en.wikipedia.org/wiki/Data-rate_units
@@ -2798,98 +2737,6 @@ static void sctp_timer_print(struct tcpstat *s)
print_ms_timer(s->timeout), s->retrans);
}
-static int tcp_show_line(char *line, const struct filter *f, int family)
-{
- int rto = 0, ato = 0;
- struct tcpstat s = {};
- char *loc, *rem, *data;
- char opt[256];
- int n;
- int hz = get_user_hz();
-
- if (proc_inet_split_line(line, &loc, &rem, &data))
- return -1;
-
- int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
-
- if (!(f->states & (1 << state)))
- return 0;
-
- proc_parse_inet_addr(loc, rem, family, &s.ss);
-
- if (f->f && run_ssfilter(f->f, &s.ss) == 0)
- return 0;
-
- opt[0] = 0;
- n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %u %d %[^\n]\n",
- &s.ss.state, &s.ss.wq, &s.ss.rq,
- &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes,
- &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd,
- &s.ssthresh, opt);
-
- if (n < 17)
- opt[0] = 0;
-
- if (n < 12) {
- rto = 0;
- s.cwnd = 2;
- s.ssthresh = -1;
- ato = s.qack = 0;
- }
-
- s.retrans = s.timer != 1 ? s.probes : s.retrans;
- s.timeout = (s.timeout * 1000 + hz - 1) / hz;
- s.ato = (double)ato / hz;
- s.qack /= 2;
- s.rto = (double)rto;
- s.ssthresh = s.ssthresh == -1 ? 0 : s.ssthresh;
- s.rto = s.rto != 3 * hz ? s.rto / hz : 0;
- s.ss.type = IPPROTO_TCP;
-
- inet_stats_print(&s.ss, false);
-
- if (show_options)
- tcp_timer_print(&s);
-
- if (show_details) {
- sock_details_print(&s.ss);
- if (opt[0])
- out(" opt:\"%s\"", opt);
- }
-
- if (show_tcpinfo)
- tcp_stats_print(&s);
-
- return 0;
-}
-
-static int generic_record_read(FILE *fp,
- int (*worker)(char*, const struct filter *, int),
- const struct filter *f, int fam)
-{
- char line[256];
-
- /* skip header */
- if (fgets(line, sizeof(line), fp) == NULL)
- goto outerr;
-
- while (fgets(line, sizeof(line), fp) != NULL) {
- int n = strlen(line);
-
- if (n == 0 || line[n-1] != '\n') {
- errno = -EINVAL;
- return -1;
- }
- line[n-1] = 0;
-
- if (worker(line, f, fam) < 0)
- return 0;
- }
-outerr:
-
- return ferror(fp) ? -1 : 0;
-}
-
static void print_skmeminfo(struct rtattr *tb[], int attrtype)
{
const __u32 *skmeminfo;
@@ -4231,10 +4078,6 @@ static int tcp_show_netlink_file(struct filter *f)
static int tcp_show(struct filter *f)
{
- FILE *fp = NULL;
- char *buf = NULL;
- int bufsize = 1024*1024;
-
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
@@ -4243,52 +4086,7 @@ static int tcp_show(struct filter *f)
if (getenv("TCPDIAG_FILE"))
return tcp_show_netlink_file(f);
- if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
- && inet_show_netlink(f, NULL, IPPROTO_TCP) == 0)
- return 0;
-
- /* Sigh... We have to parse /proc/net/tcp... */
- while (bufsize >= 64*1024) {
- if ((buf = malloc(bufsize)) != NULL)
- break;
- bufsize /= 2;
- }
- if (buf == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- if (f->families & FAMILY_MASK(AF_INET)) {
- if ((fp = net_tcp_open()) == NULL)
- goto outerr;
-
- setbuffer(fp, buf, bufsize);
- if (generic_record_read(fp, tcp_show_line, f, AF_INET))
- goto outerr;
- fclose(fp);
- }
-
- if ((f->families & FAMILY_MASK(AF_INET6)) &&
- (fp = net_tcp6_open()) != NULL) {
- setbuffer(fp, buf, bufsize);
- if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
- goto outerr;
- fclose(fp);
- }
-
- free(buf);
- return 0;
-
-outerr:
- do {
- int saved_errno = errno;
-
- free(buf);
- if (fp)
- fclose(fp);
- errno = saved_errno;
- return -1;
- } while (0);
+ return inet_show_netlink(f, NULL, IPPROTO_TCP);
}
static int mptcp_show(struct filter *f)
@@ -4296,11 +4094,7 @@ static int mptcp_show(struct filter *f)
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
- if (!getenv("PROC_NET_MPTCP") && !getenv("PROC_ROOT")
- && inet_show_netlink(f, NULL, IPPROTO_MPTCP) == 0)
- return 0;
-
- return 0;
+ return inet_show_netlink(f, NULL, IPPROTO_MPTCP);
}
static int sctp_show(struct filter *f)
@@ -4308,140 +4102,27 @@ static int sctp_show(struct filter *f)
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
- if (!getenv("PROC_NET_SCTP") && !getenv("PROC_ROOT")
- && inet_show_netlink(f, NULL, IPPROTO_SCTP) == 0)
- return 0;
-
- return 0;
-}
-
-static int dgram_show_line(char *line, const struct filter *f, int family)
-{
- struct sockstat s = {};
- char *loc, *rem, *data;
- char opt[256];
- int n;
-
- if (proc_inet_split_line(line, &loc, &rem, &data))
- return -1;
-
- int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
-
- if (!(f->states & (1 << state)))
- return 0;
-
- proc_parse_inet_addr(loc, rem, family, &s);
-
- if (f->f && run_ssfilter(f->f, &s) == 0)
- return 0;
-
- opt[0] = 0;
- n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
- &s.state, &s.wq, &s.rq,
- &s.uid, &s.ino,
- &s.refcnt, &s.sk, opt);
-
- if (n < 9)
- opt[0] = 0;
-
- s.type = dg_proto == UDP_PROTO ? IPPROTO_UDP : 0;
- inet_stats_print(&s, false);
-
- if (show_details && opt[0])
- out(" opt:\"%s\"", opt);
-
- return 0;
+ return inet_show_netlink(f, NULL, IPPROTO_SCTP);
}
static int udp_show(struct filter *f)
{
- FILE *fp = NULL;
-
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
dg_proto = UDP_PROTO;
- if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
- && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
- return 0;
-
- if (f->families&FAMILY_MASK(AF_INET)) {
- if ((fp = net_udp_open()) == NULL)
- goto outerr;
- if (generic_record_read(fp, dgram_show_line, f, AF_INET))
- goto outerr;
- fclose(fp);
- }
-
- if ((f->families&FAMILY_MASK(AF_INET6)) &&
- (fp = net_udp6_open()) != NULL) {
- if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
- goto outerr;
- fclose(fp);
- }
- return 0;
-
-outerr:
- do {
- int saved_errno = errno;
-
- if (fp)
- fclose(fp);
- errno = saved_errno;
- return -1;
- } while (0);
+ return inet_show_netlink(f, NULL, IPPROTO_UDP);
}
static int raw_show(struct filter *f)
{
- FILE *fp = NULL;
-
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
dg_proto = RAW_PROTO;
- if (!getenv("PROC_NET_RAW") && !getenv("PROC_ROOT") &&
- inet_show_netlink(f, NULL, IPPROTO_RAW) == 0)
- return 0;
-
- if (f->families&FAMILY_MASK(AF_INET)) {
- if ((fp = net_raw_open()) == NULL)
- goto outerr;
- if (generic_record_read(fp, dgram_show_line, f, AF_INET))
- goto outerr;
- fclose(fp);
- }
-
- if ((f->families&FAMILY_MASK(AF_INET6)) &&
- (fp = net_raw6_open()) != NULL) {
- if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
- goto outerr;
- fclose(fp);
- }
- return 0;
-
-outerr:
- do {
- int saved_errno = errno;
-
- if (fp)
- fclose(fp);
- errno = saved_errno;
- return -1;
- } while (0);
-}
-
-#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
-
-static void unix_list_drop_first(struct sockstat **list)
-{
- struct sockstat *s = *list;
-
- (*list) = (*list)->next;
- free(s->name);
- free(s);
+ return inet_show_netlink(f, NULL, IPPROTO_RAW);
}
static bool unix_type_skip(struct sockstat *s, struct filter *f)
@@ -4569,10 +4250,13 @@ Exit:
return ret;
}
-static int unix_show_netlink(struct filter *f)
+static int unix_show(struct filter *f)
{
DIAG_REQUEST(req, struct unix_diag_req r);
+ if (!filter_af_get(f, AF_UNIX))
+ return 0;
+
req.r.sdiag_family = AF_UNIX;
req.r.udiag_states = f->states;
req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
@@ -4584,139 +4268,6 @@ static int unix_show_netlink(struct filter *f)
return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock);
}
-static int unix_show(struct filter *f)
-{
- FILE *fp;
- char buf[256];
- char name[128];
- int newformat = 0;
- int cnt;
- struct sockstat *list = NULL;
- const int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
- SS_ESTABLISHED, SS_CLOSING };
-
- if (!filter_af_get(f, AF_UNIX))
- return 0;
-
- if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
- && unix_show_netlink(f) == 0)
- return 0;
-
- if ((fp = net_unix_open()) == NULL)
- return -1;
- if (!fgets(buf, sizeof(buf), fp)) {
- fclose(fp);
- return -1;
- }
-
- if (memcmp(buf, "Peer", 4) == 0)
- newformat = 1;
- cnt = 0;
-
- while (fgets(buf, sizeof(buf), fp)) {
- struct sockstat *u, **insp;
- int flags;
-
- if (!(u = calloc(1, sizeof(*u))))
- break;
-
- if (sscanf(buf, "%lx: %x %x %x %x %x %d %s",
- (unsigned long *)&u->rport, &u->rq, &u->wq, &flags, &u->type,
- &u->state, &u->ino, name) < 8)
- name[0] = 0;
-
- u->lport = u->ino;
- u->local.family = u->remote.family = AF_UNIX;
-
- if (flags & (1 << 16)) {
- u->state = SS_LISTEN;
- } else if (u->state > 0 &&
- u->state <= ARRAY_SIZE(unix_state_map)) {
- u->state = unix_state_map[u->state-1];
- if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
- u->state = SS_ESTABLISHED;
- }
- if (unix_type_skip(u, f) ||
- !(f->states & (1 << u->state))) {
- free(u);
- continue;
- }
-
- if (!newformat) {
- u->rport = 0;
- u->rq = 0;
- u->wq = 0;
- }
-
- if (name[0]) {
- u->name = strdup(name);
- if (!u->name) {
- free(u);
- break;
- }
- }
-
- if (u->rport) {
- struct sockstat *p;
-
- for (p = list; p; p = p->next) {
- if (u->rport == p->lport)
- break;
- }
- if (!p)
- u->peer_name = "?";
- else
- u->peer_name = p->name ? : "*";
- }
-
- if (f->f) {
- struct sockstat st = {
- .local.family = AF_UNIX,
- .remote.family = AF_UNIX,
- };
-
- memcpy(st.local.data, &u->name, sizeof(u->name));
- /* when parsing the old format rport is set to 0 and
- * therefore peer_name remains NULL
- */
- if (u->peer_name && strcmp(u->peer_name, "*"))
- memcpy(st.remote.data, &u->peer_name,
- sizeof(u->peer_name));
- if (run_ssfilter(f->f, &st) == 0) {
- free(u->name);
- free(u);
- continue;
- }
- }
-
- insp = &list;
- while (*insp) {
- if (u->type < (*insp)->type ||
- (u->type == (*insp)->type &&
- u->ino < (*insp)->ino))
- break;
- insp = &(*insp)->next;
- }
- u->next = *insp;
- *insp = u;
-
- if (++cnt > MAX_UNIX_REMEMBER) {
- while (list) {
- unix_stats_print(list, f);
- unix_list_drop_first(&list);
- }
- cnt = 0;
- }
- }
- fclose(fp);
- while (list) {
- unix_stats_print(list, f);
- unix_list_drop_first(&list);
- }
-
- return 0;
-}
-
static int packet_stats_print(struct sockstat *s, const struct filter *f)
{
const char *addr, *port;
@@ -4777,10 +4328,6 @@ static int packet_show_sock(struct nlmsghdr *nlh, void *arg)
parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- /* use /proc/net/packet if all info are not available */
- if (!tb[PACKET_DIAG_MEMINFO])
- return -1;
-
stat.type = r->pdiag_type;
stat.prot = r->pdiag_num;
stat.ino = r->pdiag_ino;
@@ -4905,10 +4452,13 @@ static int packet_show_sock(struct nlmsghdr *nlh, void *arg)
return 0;
}
-static int packet_show_netlink(struct filter *f)
+static int packet_show(struct filter *f)
{
DIAG_REQUEST(req, struct packet_diag_req r);
+ if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
+ return 0;
+
req.r.sdiag_family = AF_PACKET;
req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO |
PACKET_SHOW_FILTER | PACKET_SHOW_RING_CFG | PACKET_SHOW_FANOUT;
@@ -4916,58 +4466,6 @@ static int packet_show_netlink(struct filter *f)
return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
}
-static int packet_show_line(char *buf, const struct filter *f, int fam)
-{
- unsigned long long sk;
- struct sockstat stat = {};
- int type, prot, iface, state, rq, uid, ino;
-
- sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
- &sk,
- &type, &prot, &iface, &state,
- &rq, &uid, &ino);
-
- if (type == SOCK_RAW && !(f->dbs & (1<<PACKET_R_DB)))
- return 0;
- if (type == SOCK_DGRAM && !(f->dbs & (1<<PACKET_DG_DB)))
- return 0;
-
- stat.type = type;
- stat.prot = prot;
- stat.lport = stat.iface = iface;
- stat.state = state;
- stat.rq = rq;
- stat.uid = uid;
- stat.ino = ino;
- stat.state = SS_CLOSE;
-
- if (packet_stats_print(&stat, f))
- return 0;
-
- return 0;
-}
-
-static int packet_show(struct filter *f)
-{
- FILE *fp;
- int rc = 0;
-
- if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
- return 0;
-
- if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
- packet_show_netlink(f) == 0)
- return 0;
-
- if ((fp = net_packet_open()) == NULL)
- return -1;
- if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
- rc = -1;
-
- fclose(fp);
- return rc;
-}
-
static int xdp_stats_print(struct sockstat *s, const struct filter *f)
{
const char *addr, *port;
@@ -5263,10 +4761,13 @@ static int netlink_show_sock(struct nlmsghdr *nlh, void *arg)
return 0;
}
-static int netlink_show_netlink(struct filter *f)
+static int netlink_show(struct filter *f)
{
DIAG_REQUEST(req, struct netlink_diag_req r);
+ if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
+ return 0;
+
req.r.sdiag_family = AF_NETLINK;
req.r.sdiag_protocol = NDIAG_PROTO_ALL;
req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
@@ -5274,41 +4775,6 @@ static int netlink_show_netlink(struct filter *f)
return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock);
}
-static int netlink_show(struct filter *f)
-{
- FILE *fp;
- char buf[256];
- int prot, pid;
- unsigned int groups;
- int rq, wq, rc;
- unsigned long long sk, cb;
-
- if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
- return 0;
-
- if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
- netlink_show_netlink(f) == 0)
- return 0;
-
- if ((fp = net_netlink_open()) == NULL)
- return -1;
- if (!fgets(buf, sizeof(buf), fp)) {
- fclose(fp);
- return -1;
- }
-
- while (fgets(buf, sizeof(buf), fp)) {
- sscanf(buf, "%llx %d %d %x %d %d %llx %d",
- &sk,
- &prot, &pid, &groups, &rq, &wq, &cb, &rc);
-
- netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
- }
-
- fclose(fp);
- return 0;
-}
-
static bool vsock_type_skip(struct sockstat *s, struct filter *f)
{
if (s->type == SOCK_STREAM && !(f->dbs & (1 << VSOCK_ST_DB)))
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [RFC iproute2-next] ss: remove /proc fallback paths
2026-09-01 14:38 [RFC iproute2-next] ss: remove /proc fallback paths Stephen Hemminger
@ 2026-10-18 20:07 ` Gopal Malaviya
0 siblings, 0 replies; 2+ messages in thread
From: Gopal Malaviya @ 2026-10-18 20:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
On Tue, 1 Sep 2026 14:38 UTC, Stephen Hemminger wrote:
> This patch removes the old /proc/net fallback code in ss command.
> The sock_diag netlink interfaces were all in 3.10, over 13 years ago.
> No longer need to carry all the additional text parsing code.
I tested this on top of iproute2-next (204a7210). It builds with no new
warnings, testsuite/tests/ss/ssfilter.t passes, and on a WSL2 6.18
kernel the output of ss -tan, -uan, -xan, -s and -tanpie is identical
with and without the patch (ss -a -A netlink too, apart from the line
for ss's own netlink socket).
One concern: the diag interfaces are in the kernel, but each one is a
separate Kconfig option. INET_DIAG defaults to y, while UNIX_DIAG,
PACKET_DIAG, NETLINK_DIAG, INET_UDP_DIAG and INET_RAW_DIAG are all
"default n", and common configs leave some of them off:
x86_64_defconfig has "# CONFIG_INET_DIAG is not set", arm64 defconfig
sets none of the five, and Android's gki_defconfig enables only
INET_UDP_DIAG among them.
When the interface for a socket type is missing, ss currently falls
back to /proc/net/*. With this patch it prints only the header and
exits 0, so those sockets silently disappear. I reproduced this for
raw, unix and packet sockets (ss_before/ss_after are ss built
without/with this patch). Raw sockets, on a kernel without
INET_RAW_DIAG (the stock WSL2 kernel), with one ICMP and one ICMPv6 raw
socket open:
# uname -r
6.18.54.1-microsoft-standard-WSL2
# zcat /proc/config.gz | grep INET_RAW_DIAG
# CONFIG_INET_RAW_DIAG is not set
# ss_before -wa
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 0.0.0.0:icmp 0.0.0.0:*
UNCONN 0 0 *:ipv6-icmp *:*
# ss_after -wa
State Recv-Q Send-Q Local Address:Port Peer Address:Port
# echo $?
0
Unix and packet sockets, on a kernel where unix_diag and packet_diag
are modules that cannot be loaded (a WSL 6.6 kernel booted without its
modules), with one packet socket open:
# zcat /proc/config.gz | grep -E 'CONFIG_(UNIX_DIAG|PACKET_DIAG)='
CONFIG_PACKET_DIAG=m
CONFIG_UNIX_DIAG=m
# modprobe unix_diag
modprobe: FATAL: Module unix_diag not found in directory /lib/modules/6.6.114.1-microsoft-standard-WSL2-destroy+
# tail -n +2 /proc/net/unix | wc -l
171
# ss_before -xa | tail -n +2 | wc -l
171
# ss_after -xa | tail -n +2 | wc -l
0
# ss_before -0a
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
p_raw UNCONN 896 0 *:* *
# ss_after -0a
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
Distribution kernels such as Ubuntu's 6.8.0-147-generic and Arch's
linux package build all of them as modules, so they are not affected.
I did not boot an x86_64_defconfig kernel; I would expect ss -t to
show nothing there for the same reason, since INET_DIAG is off.
I may be missing context on how much these configurations matter for
ss, so please take this only as a data point. If it is useful, I would
be glad to help test any further changes in this area.
Thanks,
Gopal Malaviya
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-18 20:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 14:38 [RFC iproute2-next] ss: remove /proc fallback paths Stephen Hemminger
2026-10-18 20:07 ` Gopal Malaviya
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.