#include "rt_names.h"
#include "ll_map.h"
#include "libnetlink.h"
+#include "namespace.h"
#include "SNAPSHOT.h"
#include <linux/tcp.h>
static void filter_af_set(struct filter *f, int af)
{
- f->dbs |= default_afs[af].dbs;
- f->states |= default_afs[af].states;
- f->families |= 1 << af;
- do_default = 0;
+ f->dbs |= default_afs[af].dbs;
+ f->states |= default_afs[af].states;
+ f->families |= 1 << af;
+ do_default = 0;
+ preferred_family = af;
}
static int filter_af_get(struct filter *f, int af)
int skbs;
};
-struct slabstat slabstat;
+static struct slabstat slabstat;
static const char *slabstat_ids[] =
{
char buf[256];
FILE *fp;
int cnt;
+ static int slabstat_valid;
+
+ if (slabstat_valid)
+ return 0;
memset(s, 0, sizeof(*s));
break;
}
+ slabstat_valid = 1;
+
fclose(fp);
return 0;
}
+static inline void sock_addr_set_str(inet_prefix *prefix, char **ptr)
+{
+ memcpy(prefix->data, ptr, sizeof(char *));
+}
+
+static inline char *sock_addr_get_str(const inet_prefix *prefix)
+{
+ char *tmp ;
+ memcpy(&tmp, prefix->data, sizeof(char *));
+ return tmp;
+}
+
+static unsigned long cookie_sk_get(uint32_t *cookie)
+{
+ return (((unsigned long)cookie[1] << 31) << 1) | cookie[0];
+}
+
static const char *sstate_name[] = {
"UNKNOWN",
[SS_ESTABLISHED] = "ESTAB",
[SS_CLOSING] = "closing",
};
+struct sockstat
+{
+ struct sockstat *next;
+ unsigned int type;
+ uint16_t prot;
+ inet_prefix local;
+ inet_prefix remote;
+ int lport;
+ int rport;
+ int state;
+ int rq, wq;
+ unsigned ino;
+ unsigned uid;
+ int refcnt;
+ unsigned int iface;
+ unsigned long long sk;
+};
+
+struct dctcpstat
+{
+ unsigned int ce_state;
+ unsigned int alpha;
+ unsigned int ab_ecn;
+ unsigned int ab_tot;
+ bool enabled;
+};
+
struct tcpstat
{
- inet_prefix local;
- inet_prefix remote;
- int lport;
- int rport;
- int state;
- int rq, wq;
- int timer;
- int timeout;
- int retrs;
- unsigned ino;
- int probes;
- unsigned uid;
- int refcnt;
- unsigned long long sk;
- int rto, ato, qack, cwnd, ssthresh;
+ struct sockstat ss;
+ int timer;
+ int timeout;
+ int probes;
+ char *cong_alg;
+ double rto, ato, rtt, rttvar;
+ int qack, cwnd, ssthresh, backoff;
+ double send_bps;
+ int snd_wscale;
+ int rcv_wscale;
+ int mss;
+ unsigned int lastsnd;
+ unsigned int lastrcv;
+ unsigned int lastack;
+ double pacing_rate;
+ double pacing_rate_max;
+ unsigned int unacked;
+ unsigned int retrans;
+ unsigned int retrans_total;
+ unsigned int lost;
+ unsigned int sacked;
+ unsigned int fackets;
+ unsigned int reordering;
+ double rcv_rtt;
+ int rcv_space;
+ bool has_ts_opt;
+ bool has_sack_opt;
+ bool has_ecn_opt;
+ bool has_ecnseen_opt;
+ bool has_fastopen_opt;
+ bool has_wscale_opt;
+ struct dctcpstat *dctcp;
};
+static void sock_state_print(struct sockstat *s, const char *sock_name)
+{
+ if (netid_width)
+ printf("%-*s ", netid_width, sock_name);
+ if (state_width)
+ printf("%-*s ", state_width, sstate_name[s->state]);
+
+ printf("%-6d %-6d ", s->rq, s->wq);
+}
+
+static void sock_details_print(struct sockstat *s)
+{
+ if (s->uid)
+ printf(" uid:%u", s->uid);
+
+ printf(" ino:%u", s->ino);
+ printf(" sk:%llx", s->sk);
+}
+
+static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
+ int port_len, const char *port, const char *ifname)
+{
+ if (ifname) {
+ printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
+ port_len, port);
+ }
+ else {
+ printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
+ }
+}
+
+static void sock_addr_print(const char *addr, char *delim, const char *port,
+ const char *ifname)
+{
+ sock_addr_print_width(addr_width, addr, delim, serv_width, port, ifname);
+}
+
static const char *tmr_name[] = {
"off",
"on",
return buf;
}
-static const char *print_hz_timer(int timeout)
-{
- int hz = get_user_hz();
- return print_ms_timer(((timeout*1000) + hz-1)/hz);
-}
-
struct scache
{
struct scache *next;
return buf;
}
-static void formatted_print(const inet_prefix *a, int port, unsigned int ifindex)
+static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex)
{
char buf[1024];
const char *ap = buf;
- int est_len;
-
- est_len = addr_width;
+ int est_len = addr_width;
+ const char *ifname = NULL;
if (a->family == AF_INET) {
if (a->data[0] == 0) {
else
est_len = addr_width + ((est_len-addr_width+3)/4)*4;
}
+
if (ifindex) {
- const char *ifname = ll_index_to_name(ifindex);
- const int len = strlen(ifname) + 1; /* +1 for percent char */
+ ifname = ll_index_to_name(ifindex);
+ est_len -= strlen(ifname) + 1; /* +1 for percent char */
+ }
- printf("%*s%%%s:%-*s ", est_len - len, ap, ifname, serv_width,
- resolve_service(port));
- } else
- printf("%*s:%-*s ", est_len, ap, serv_width, resolve_service(port));
+ sock_addr_print_width(est_len, ap, ":", serv_width, resolve_service(port),
+ ifname);
}
struct aafilter
static int unix_match(const inet_prefix *a, const inet_prefix *p)
{
- char *addr, *pattern;
- memcpy(&addr, a->data, sizeof(addr));
- memcpy(&pattern, p->data, sizeof(pattern));
+ char *addr = sock_addr_get_str(a);
+ char *pattern = sock_addr_get_str(p);
+
if (pattern == NULL)
return 1;
if (addr == NULL)
return !fnmatch(pattern, addr, 0);
}
-static int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
+static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
{
switch (f->type) {
case SSF_S_AUTO:
static int low, high=65535;
if (s->local.family == AF_UNIX) {
- char *p;
- memcpy(&p, s->local.data, sizeof(p));
+ char *p = sock_addr_get_str(&s->local);
return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
strspn(p+1, "0123456789abcdef") == 5);
}
return ll_name_to_index(dev);
}
-void *parse_hostcond(char *addr)
+void *parse_hostcond(char *addr, bool is_port)
{
char *port = NULL;
- struct aafilter a;
+ struct aafilter a = { .port = -1 };
struct aafilter *res;
- int fam = 0;
+ int fam = preferred_family;
struct filter *f = ¤t_filter;
- memset(&a, 0, sizeof(a));
- a.port = -1;
-
- if (filter_af_get(f, AF_UNIX) || strncmp(addr, "unix:", 5) == 0) {
+ if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
char *p;
a.addr.family = AF_UNIX;
if (strncmp(addr, "unix:", 5) == 0)
addr+=5;
p = strdup(addr);
a.addr.bitlen = 8*strlen(p);
- memcpy(a.addr.data, &p, sizeof(p));
+ sock_addr_set_str(&a.addr, &p);
fam = AF_UNIX;
goto out;
}
- if (filter_af_get(f, AF_PACKET) || strncmp(addr, "link:", 5) == 0) {
+ if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) {
a.addr.family = AF_PACKET;
a.addr.bitlen = 0;
if (strncmp(addr, "link:", 5) == 0)
goto out;
}
- if (filter_af_get(f, AF_NETLINK) || strncmp(addr, "netlink:", 8) == 0) {
+ if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) {
a.addr.family = AF_NETLINK;
a.addr.bitlen = 0;
if (strncmp(addr, "netlink:", 8) == 0)
goto out;
}
- if (filter_af_get(f, AF_INET) || !strncmp(addr, "inet:", 5)) {
- addr += 5;
+ if (fam == AF_INET || !strncmp(addr, "inet:", 5)) {
fam = AF_INET;
- } else if (filter_af_get(f, AF_INET6) || !strncmp(addr, "inet6:", 6)) {
- addr += 6;
+ if (!strncmp(addr, "inet:", 5))
+ addr += 5;
+ } else if (fam == AF_INET6 || !strncmp(addr, "inet6:", 6)) {
fam = AF_INET6;
+ if (!strncmp(addr, "inet6:", 6))
+ addr += 6;
}
/* URL-like literal [] */
} else {
port = strrchr(strchr(addr, '/') ? : addr, ':');
}
+
+ if (is_port)
+ port = addr;
+
if (port && *port) {
- if (*port != ':')
- return NULL;
- *port++ = 0;
+ if (*port == ':')
+ *port++ = 0;
+
if (*port && *port != '*') {
if (get_integer(&a.port, port, 0)) {
struct servent *se1 = NULL;
}
}
}
- if (addr && *addr && *addr != '*') {
+ if (!is_port && addr && *addr && *addr != '*') {
if (get_prefix_1(&a.addr, addr, fam)) {
if (get_dns_host(&a, addr, fam)) {
fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
}
out:
- if (fam)
+ if (fam != AF_UNSPEC) {
+ f->families = 0;
filter_af_set(f, fam);
+ filter_merge(f, f, 0);
+ }
res = malloc(sizeof(*res));
if (res)
return res;
}
-static int tcp_show_line(char *line, const struct filter *f, int family)
+static char *proto_name(int protocol)
+{
+ switch (protocol) {
+ case IPPROTO_UDP:
+ return "udp";
+ case IPPROTO_TCP:
+ return "tcp";
+ case IPPROTO_DCCP:
+ return "dccp";
+ }
+
+ return "???";
+}
+
+static void inet_stats_print(struct sockstat *s, int protocol)
+{
+ char *buf = NULL;
+
+ sock_state_print(s, proto_name(protocol));
+
+ inet_addr_print(&s->local, s->lport, s->iface);
+ inet_addr_print(&s->remote, s->rport, 0);
+
+ if (show_proc_ctx || show_sock_ctx) {
+ if (find_entry(s->ino, &buf,
+ (show_proc_ctx & show_sock_ctx) ?
+ PROC_SOCK_CTX : PROC_CTX) > 0) {
+ printf(" users:(%s)", buf);
+ free(buf);
+ }
+ } else if (show_users) {
+ if (find_entry(s->ino, &buf, USERS) > 0) {
+ printf(" users:(%s)", buf);
+ free(buf);
+ }
+ }
+}
+
+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:%x", s->local.data, (unsigned*)&s->lport);
+ sscanf(rem, "%x:%x", s->remote.data, (unsigned*)&s->rport);
+ s->local.bytelen = s->remote.bytelen = 4;
+ return 0;
+ } else {
+ sscanf(loc, "%08x%08x%08x%08x:%x",
+ s->local.data,
+ s->local.data + 1,
+ s->local.data + 2,
+ s->local.data + 3,
+ &s->lport);
+ sscanf(rem, "%08x%08x%08x%08x:%x",
+ s->remote.data,
+ s->remote.data + 1,
+ s->remote.data + 2,
+ s->remote.data + 3,
+ &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)
{
- struct tcpstat s;
- char *loc, *rem, *data;
- char opt[256];
- int n;
char *p;
if ((p = strchr(line, ':')) == NULL)
return -1;
- loc = p+2;
- if ((p = strchr(loc, ':')) == NULL)
+ *loc = p+2;
+ if ((p = strchr(*loc, ':')) == NULL)
return -1;
- p[5] = 0;
- rem = p+6;
- if ((p = strchr(rem, ':')) == NULL)
+ p[5] = 0;
+ *rem = p+6;
+ if ((p = strchr(*rem, ':')) == NULL)
return -1;
+
p[5] = 0;
- data = p+6;
+ *data = p+6;
+ return 0;
+}
- do {
- int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
+static char *sprint_bw(char *buf, double bw)
+{
+ if (bw > 1000000.)
+ sprintf(buf,"%.1fM", bw / 1000000.);
+ else if (bw > 1000.)
+ sprintf(buf,"%.1fK", bw / 1000.);
+ else
+ sprintf(buf, "%g", bw);
- if (!(f->states & (1<<state)))
- return 0;
- } while (0);
+ return buf;
+}
- s.local.family = s.remote.family = family;
- if (family == AF_INET) {
- sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
- sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
- s.local.bytelen = s.remote.bytelen = 4;
- } else {
- sscanf(loc, "%08x%08x%08x%08x:%x",
- s.local.data,
- s.local.data+1,
- s.local.data+2,
- s.local.data+3,
- &s.lport);
- sscanf(rem, "%08x%08x%08x%08x:%x",
- s.remote.data,
- s.remote.data+1,
- s.remote.data+2,
- s.remote.data+3,
- &s.rport);
- s.local.bytelen = s.remote.bytelen = 16;
+static void tcp_stats_print(struct tcpstat *s)
+{
+ char b1[64];
+
+ if (s->has_ts_opt)
+ printf(" ts");
+ if (s->has_sack_opt)
+ printf(" sack");
+ if (s->has_ecn_opt)
+ printf(" ecn");
+ if (s->has_ecnseen_opt)
+ printf(" ecnseen");
+ if (s->has_fastopen_opt)
+ printf(" fastopen");
+ if (s->cong_alg)
+ printf(" %s", s->cong_alg);
+ if (s->has_wscale_opt)
+ printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
+ if (s->rto)
+ printf(" rto:%g", s->rto);
+ if (s->backoff)
+ printf(" backoff:%u", s->backoff);
+ if (s->rtt)
+ printf(" rtt:%g/%g", s->rtt, s->rttvar);
+ if (s->ato)
+ printf(" ato:%g", s->ato);
+
+ if (s->qack)
+ printf(" qack:%d", s->qack);
+ if (s->qack & 1)
+ printf(" bidir");
+
+ if (s->mss)
+ printf(" mss:%d", s->mss);
+ if (s->cwnd && s->cwnd != 2)
+ printf(" cwnd:%d", s->cwnd);
+ if (s->ssthresh)
+ printf(" ssthresh:%d", s->ssthresh);
+
+ if (s->dctcp && s->dctcp->enabled) {
+ struct dctcpstat *dctcp = s->dctcp;
+
+ printf("dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
+ dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
+ dctcp->ab_tot);
+ } else if (s->dctcp) {
+ printf("dctcp:fallback_mode");
+ }
+
+ if (s->send_bps)
+ printf(" send %sbps", sprint_bw(b1, s->send_bps));
+ if (s->lastsnd)
+ printf(" lastsnd:%u", s->lastsnd);
+ if (s->lastrcv)
+ printf(" lastrcv:%u", s->lastrcv);
+ if (s->lastack)
+ printf(" lastack:%u", s->lastack);
+
+ if (s->pacing_rate) {
+ printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
+ if (s->pacing_rate_max)
+ printf("/%sbps", sprint_bw(b1,
+ s->pacing_rate_max));
+ }
+
+ if (s->unacked)
+ printf(" unacked:%u", s->unacked);
+ if (s->retrans || s->retrans_total)
+ printf(" retrans:%u/%u", s->retrans, s->retrans_total);
+ if (s->lost)
+ printf(" lost:%u", s->lost);
+ if (s->sacked && s->ss.state != SS_LISTEN)
+ printf(" sacked:%u", s->sacked);
+ if (s->fackets)
+ printf(" fackets:%u", s->fackets);
+ if (s->reordering != 3)
+ printf(" reordering:%d", s->reordering);
+ if (s->rcv_rtt)
+ printf(" rcv_rtt:%g", s->rcv_rtt);
+ if (s->rcv_space)
+ printf(" rcv_space:%d", s->rcv_space);
+}
+
+static void tcp_timer_print(struct tcpstat *s)
+{
+ if (s->timer) {
+ if (s->timer > 4)
+ s->timer = 5;
+ printf(" timer:(%s,%s,%d)",
+ tmr_name[s->timer],
+ print_ms_timer(s->timeout),
+ s->retrans);
}
+}
- if (f->f && run_ssfilter(f->f, &s) == 0)
+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 %d %d %[^\n]\n",
- &s.state, &s.wq, &s.rq,
- &s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
- &s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
- &s.cwnd, &s.ssthresh, opt);
+ &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) {
- s.rto = 0;
+ rto = 0;
s.cwnd = 2;
s.ssthresh = -1;
- s.ato = s.qack = 0;
+ ato = s.qack = 0;
}
- if (netid_width)
- printf("%-*s ", netid_width, "tcp");
- if (state_width)
- printf("%-*s ", state_width, sstate_name[s.state]);
-
- printf("%-6d %-6d ", s.rq, s.wq);
+ 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;
- formatted_print(&s.local, s.lport, 0);
- formatted_print(&s.remote, s.rport, 0);
+ inet_stats_print(&s.ss, IPPROTO_TCP);
- if (show_options) {
- if (s.timer) {
- if (s.timer > 4)
- s.timer = 5;
- printf(" timer:(%s,%s,%d)",
- tmr_name[s.timer],
- print_hz_timer(s.timeout),
- s.timer != 1 ? s.probes : s.retrs);
- }
- }
- if (show_tcpinfo) {
- int hz = get_user_hz();
- if (s.rto && s.rto != 3*hz)
- printf(" rto:%g", (double)s.rto/hz);
- if (s.ato)
- printf(" ato:%g", (double)s.ato/hz);
- if (s.cwnd != 2)
- printf(" cwnd:%d", s.cwnd);
- if (s.ssthresh != -1)
- printf(" ssthresh:%d", s.ssthresh);
- if (s.qack/2)
- printf(" qack:%d", s.qack/2);
- if (s.qack&1)
- printf(" bidir");
- }
- char *buf = NULL;
- if (show_proc_ctx || show_sock_ctx) {
- if (find_entry(s.ino, &buf,
- (show_proc_ctx & show_sock_ctx) ?
- PROC_SOCK_CTX : PROC_CTX) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
- } else if (show_users) {
- if (find_entry(s.ino, &buf, USERS) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
- }
+ if (show_options)
+ tcp_timer_print(&s);
if (show_details) {
- if (s.uid)
- printf(" uid:%u", (unsigned)s.uid);
- printf(" ino:%u", s.ino);
- printf(" sk:%llx", s.sk);
+ sock_details_print(&s.ss);
if (opt[0])
printf(" opt:\"%s\"", opt);
}
- printf("\n");
+ if (show_tcpinfo)
+ tcp_stats_print(&s);
+
+ printf("\n");
return 0;
}
return ferror(fp) ? -1 : 0;
}
-static char *sprint_bw(char *buf, double bw)
-{
- if (bw > 1000000.)
- sprintf(buf,"%.1fM", bw / 1000000.);
- else if (bw > 1000.)
- sprintf(buf,"%.1fK", bw / 1000.);
- else
- sprintf(buf, "%g", bw);
-
- return buf;
-}
-
static void print_skmeminfo(struct rtattr *tb[], int attrtype)
{
const __u32 *skmeminfo;
- if (!tb[attrtype])
+
+ if (!tb[attrtype]) {
+ if (attrtype == INET_DIAG_SKMEMINFO) {
+ if (!tb[INET_DIAG_MEMINFO])
+ return;
+
+ const struct inet_diag_meminfo *minfo =
+ RTA_DATA(tb[INET_DIAG_MEMINFO]);
+
+ printf(" mem:(r%u,w%u,f%u,t%u)",
+ minfo->idiag_rmem,
+ minfo->idiag_wmem,
+ minfo->idiag_fmem,
+ minfo->idiag_tmem);
+ }
return;
+ }
+
skmeminfo = RTA_DATA(tb[attrtype]);
printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
printf(")");
}
+#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
+
static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
struct rtattr *tb[])
{
- char b1[64];
double rtt = 0;
+ struct tcpstat s = {};
- if (tb[INET_DIAG_SKMEMINFO]) {
- print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
- } else if (tb[INET_DIAG_MEMINFO]) {
- const struct inet_diag_meminfo *minfo
- = RTA_DATA(tb[INET_DIAG_MEMINFO]);
- printf(" mem:(r%u,w%u,f%u,t%u)",
- minfo->idiag_rmem,
- minfo->idiag_wmem,
- minfo->idiag_fmem,
- minfo->idiag_tmem);
- }
+ s.ss.state = r->idiag_state;
+
+ print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
if (tb[INET_DIAG_INFO]) {
struct tcp_info *info;
info = RTA_DATA(tb[INET_DIAG_INFO]);
if (show_options) {
- if (info->tcpi_options & TCPI_OPT_TIMESTAMPS)
- printf(" ts");
- if (info->tcpi_options & TCPI_OPT_SACK)
- printf(" sack");
- if (info->tcpi_options & TCPI_OPT_ECN)
- printf(" ecn");
- if (info->tcpi_options & TCPI_OPT_ECN_SEEN)
- printf(" ecnseen");
- if (info->tcpi_options & TCPI_OPT_SYN_DATA)
- printf(" fastopen");
+ s.has_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS);
+ s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK);
+ s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN);
+ s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN);
+ s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA);
+ }
+
+ if (tb[INET_DIAG_CONG]) {
+ const char *cong_attr = rta_getattr_str(tb[INET_DIAG_CONG]);
+ s.cong_alg = malloc(strlen(cong_attr + 1));
+ strcpy(s.cong_alg, cong_attr);
}
- if (tb[INET_DIAG_CONG])
- printf(" %s", rta_getattr_str(tb[INET_DIAG_CONG]));
+ if (TCPI_HAS_OPT(info, TCPI_OPT_WSCALE)) {
+ s.has_wscale_opt = true;
+ s.snd_wscale = info->tcpi_snd_wscale;
+ s.rcv_wscale = info->tcpi_rcv_wscale;
+ }
- if (info->tcpi_options & TCPI_OPT_WSCALE)
- printf(" wscale:%d,%d", info->tcpi_snd_wscale,
- info->tcpi_rcv_wscale);
if (info->tcpi_rto && info->tcpi_rto != 3000000)
- printf(" rto:%g", (double)info->tcpi_rto/1000);
- if (info->tcpi_backoff)
- printf(" backoff:%u", info->tcpi_backoff);
- if (info->tcpi_rtt)
- printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000,
- (double)info->tcpi_rttvar/1000);
- if (info->tcpi_ato)
- printf(" ato:%g", (double)info->tcpi_ato/1000);
- if (info->tcpi_snd_mss)
- printf(" mss:%d", info->tcpi_snd_mss);
- if (info->tcpi_snd_cwnd != 2)
- printf(" cwnd:%d", info->tcpi_snd_cwnd);
+ s.rto = (double)info->tcpi_rto / 1000;
+
+ s.backoff = info->tcpi_backoff;
+ s.rtt = (double)info->tcpi_rtt / 1000;
+ s.rttvar = (double)info->tcpi_rttvar / 1000;
+ s.ato = (double)info->tcpi_ato / 1000;
+ s.mss = info->tcpi_snd_mss;
+ s.rcv_space = info->tcpi_rcv_space;
+ s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000;
+ s.lastsnd = info->tcpi_last_data_sent;
+ s.lastrcv = info->tcpi_last_data_recv;
+ s.lastack = info->tcpi_last_ack_recv;
+ s.unacked = info->tcpi_unacked;
+ s.retrans = info->tcpi_retrans;
+ s.retrans_total = info->tcpi_total_retrans;
+ s.lost = info->tcpi_lost;
+ s.sacked = info->tcpi_sacked;
+ s.reordering = info->tcpi_reordering;
+ s.rcv_space = info->tcpi_rcv_space;
+ s.cwnd = info->tcpi_snd_cwnd;
+
if (info->tcpi_snd_ssthresh < 0xFFFF)
- printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
+ s.ssthresh = info->tcpi_snd_ssthresh;
rtt = (double) info->tcpi_rtt;
if (tb[INET_DIAG_VEGASINFO]) {
= RTA_DATA(tb[INET_DIAG_VEGASINFO]);
if (vinfo->tcpv_enabled &&
- vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
+ vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
rtt = vinfo->tcpv_rtt;
}
if (tb[INET_DIAG_DCTCPINFO]) {
+ struct dctcpstat *dctcp = malloc(sizeof(struct
+ dctcpstat));
+
const struct tcp_dctcp_info *dinfo
= RTA_DATA(tb[INET_DIAG_DCTCPINFO]);
- if (dinfo->dctcp_enabled) {
- printf(" ce_state %u alpha %u ab_ecn %u ab_tot %u",
- dinfo->dctcp_ce_state, dinfo->dctcp_alpha,
- dinfo->dctcp_ab_ecn, dinfo->dctcp_ab_tot);
- } else {
- printf(" fallback_mode");
- }
+ dctcp->enabled = !!dinfo->dctcp_enabled;
+ dctcp->ce_state = dinfo->dctcp_ce_state;
+ dctcp->alpha = dinfo->dctcp_alpha;
+ dctcp->ab_ecn = dinfo->dctcp_ab_ecn;
+ dctcp->ab_tot = dinfo->dctcp_ab_tot;
+ s.dctcp = dctcp;
}
if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
- printf(" send %sbps",
- sprint_bw(b1, (double) info->tcpi_snd_cwnd *
- (double) info->tcpi_snd_mss * 8000000.
- / rtt));
+ s.send_bps = (double) info->tcpi_snd_cwnd *
+ (double)info->tcpi_snd_mss * 8000000. / rtt;
}
- if (info->tcpi_last_data_sent)
- printf(" lastsnd:%u", info->tcpi_last_data_sent);
-
- if (info->tcpi_last_data_recv)
- printf(" lastrcv:%u", info->tcpi_last_data_recv);
-
- if (info->tcpi_last_ack_recv)
- printf(" lastack:%u", info->tcpi_last_ack_recv);
-
if (info->tcpi_pacing_rate &&
- info->tcpi_pacing_rate != ~0ULL) {
- printf(" pacing_rate %sbps",
- sprint_bw(b1, info->tcpi_pacing_rate * 8.));
+ info->tcpi_pacing_rate != ~0ULL) {
+ s.pacing_rate = info->tcpi_pacing_rate * 8.;
if (info->tcpi_max_pacing_rate &&
- info->tcpi_max_pacing_rate != ~0ULL)
- printf("/%sbps",
- sprint_bw(b1, info->tcpi_max_pacing_rate * 8.));
+ info->tcpi_max_pacing_rate != ~0ULL)
+ s.pacing_rate_max = info->tcpi_max_pacing_rate * 8.;
}
- if (info->tcpi_unacked)
- printf(" unacked:%u", info->tcpi_unacked);
- if (info->tcpi_retrans || info->tcpi_total_retrans)
- printf(" retrans:%u/%u", info->tcpi_retrans,
- info->tcpi_total_retrans);
- if (info->tcpi_lost)
- printf(" lost:%u", info->tcpi_lost);
- if (info->tcpi_sacked && r->idiag_state != SS_LISTEN)
- printf(" sacked:%u", info->tcpi_sacked);
- if (info->tcpi_fackets)
- printf(" fackets:%u", info->tcpi_fackets);
- if (info->tcpi_reordering != 3)
- printf(" reordering:%d", info->tcpi_reordering);
- if (info->tcpi_rcv_rtt)
- printf(" rcv_rtt:%g", (double) info->tcpi_rcv_rtt/1000);
- if (info->tcpi_rcv_space)
- printf(" rcv_space:%d", info->tcpi_rcv_space);
-
- }
-}
-
-static char *proto_name(int protocol)
-{
- switch (protocol) {
- case IPPROTO_UDP:
- return "udp";
- case IPPROTO_TCP:
- return "tcp";
- case IPPROTO_DCCP:
- return "dccp";
+ tcp_stats_print(&s);
+ if (s.dctcp)
+ free(s.dctcp);
+ if (s.cong_alg)
+ free(s.cong_alg);
}
-
- return "???";
}
static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
{
struct rtattr * tb[INET_DIAG_MAX+1];
struct inet_diag_msg *r = NLMSG_DATA(nlh);
- struct tcpstat s;
+ struct sockstat s = {};
parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- s.state = r->idiag_state;
- s.local.family = s.remote.family = r->idiag_family;
- s.lport = ntohs(r->id.idiag_sport);
- s.rport = ntohs(r->id.idiag_dport);
+ s.state = r->idiag_state;
+ s.local.family = s.remote.family = r->idiag_family;
+ s.lport = ntohs(r->id.idiag_sport);
+ s.rport = ntohs(r->id.idiag_dport);
+ s.wq = r->idiag_wqueue;
+ s.rq = r->idiag_rqueue;
+ s.ino = r->idiag_inode;
+ s.uid = r->idiag_uid;
+ s.iface = r->id.idiag_if;
+ s.sk = cookie_sk_get(&r->id.idiag_cookie[0]);
+
if (s.local.family == AF_INET) {
s.local.bytelen = s.remote.bytelen = 4;
} else {
s.local.bytelen = s.remote.bytelen = 16;
}
+
memcpy(s.local.data, r->id.idiag_src, s.local.bytelen);
memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen);
if (f && f->f && run_ssfilter(f->f, &s) == 0)
return 0;
- if (netid_width)
- printf("%-*s ", netid_width, proto_name(protocol));
- if (state_width)
- printf("%-*s ", state_width, sstate_name[s.state]);
-
- printf("%-6d %-6d ", r->idiag_rqueue, r->idiag_wqueue);
-
- formatted_print(&s.local, s.lport, r->id.idiag_if);
- formatted_print(&s.remote, s.rport, 0);
+ inet_stats_print(&s, protocol);
if (show_options) {
- if (r->idiag_timer) {
- if (r->idiag_timer > 4)
- r->idiag_timer = 5;
- printf(" timer:(%s,%s,%d)",
- tmr_name[r->idiag_timer],
- print_ms_timer(r->idiag_expires),
- r->idiag_retrans);
- }
- }
- char *buf = NULL;
+ struct tcpstat t = {};
- if (show_proc_ctx || show_sock_ctx) {
- if (find_entry(r->idiag_inode, &buf,
- (show_proc_ctx & show_sock_ctx) ?
- PROC_SOCK_CTX : PROC_CTX) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
- } else if (show_users) {
- if (find_entry(r->idiag_inode, &buf, USERS) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
+ t.timer = r->idiag_timer;
+ t.timeout = r->idiag_expires;
+ t.retrans = r->idiag_retrans;
+ tcp_timer_print(&t);
}
if (show_details) {
- if (r->idiag_uid)
- printf(" uid:%u", (unsigned)r->idiag_uid);
- printf(" ino:%u", r->idiag_inode);
- printf(" sk:");
- if (r->id.idiag_cookie[1] != 0)
- printf("%08x", r->id.idiag_cookie[1]);
- printf("%08x", r->id.idiag_cookie[0]);
+ sock_details_print(&s);
if (tb[INET_DIAG_SHUTDOWN]) {
unsigned char mask;
mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
+
if (show_mem || show_tcpinfo) {
printf("\n\t");
tcp_show_info(nlh, r, tb);
}
printf("\n");
-
return 0;
}
char *buf = NULL;
int bufsize = 64*1024;
+ if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
+ return 0;
+
dg_proto = TCP_PROTO;
if (getenv("TCPDIAG_FILE"))
* it is able to give us some memory for snapshot.
*/
if (1) {
+ get_slabstat(&slabstat);
+
int guess = slabstat.socks+slabstat.tcp_syns;
if (f->states&(1<<SS_TIME_WAIT))
guess += slabstat.tcp_tws;
static int dgram_show_line(char *line, const struct filter *f, int family)
{
- struct tcpstat s;
+ struct sockstat s = {};
char *loc, *rem, *data;
char opt[256];
int n;
- char *p;
-
- if ((p = strchr(line, ':')) == NULL)
- return -1;
- loc = p+2;
- if ((p = strchr(loc, ':')) == NULL)
+ if (proc_inet_split_line(line, &loc, &rem, &data))
return -1;
- p[5] = 0;
- rem = p+6;
-
- if ((p = strchr(rem, ':')) == NULL)
- return -1;
- p[5] = 0;
- data = p+6;
-
- do {
- int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
- if (!(f->states & (1<<state)))
- return 0;
- } while (0);
+ int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
+ if (!(f->states & (1 << state)))
+ return 0;
- s.local.family = s.remote.family = family;
- if (family == AF_INET) {
- sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
- sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
- s.local.bytelen = s.remote.bytelen = 4;
- } else {
- sscanf(loc, "%08x%08x%08x%08x:%x",
- s.local.data,
- s.local.data+1,
- s.local.data+2,
- s.local.data+3,
- &s.lport);
- sscanf(rem, "%08x%08x%08x%08x:%x",
- s.remote.data,
- s.remote.data+1,
- s.remote.data+2,
- s.remote.data+3,
- &s.rport);
- s.local.bytelen = s.remote.bytelen = 16;
- }
+ proc_parse_inet_addr(loc, rem, family, &s);
if (f->f && run_ssfilter(f->f, &s) == 0)
return 0;
if (n < 9)
opt[0] = 0;
- if (netid_width)
- printf("%-*s ", netid_width, dg_proto);
- if (state_width)
- printf("%-*s ", state_width, sstate_name[s.state]);
-
- printf("%-6d %-6d ", s.rq, s.wq);
+ inet_stats_print(&s, IPPROTO_UDP);
- formatted_print(&s.local, s.lport, 0);
- formatted_print(&s.remote, s.rport, 0);
+ if (show_details && opt[0])
+ printf(" opt:\"%s\"", opt);
- char *buf = NULL;
-
- if (show_proc_ctx || show_sock_ctx) {
- if (find_entry(s.ino, &buf,
- (show_proc_ctx & show_sock_ctx) ?
- PROC_SOCK_CTX : PROC_CTX) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
- } else if (show_users) {
- if (find_entry(s.ino, &buf, USERS) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
- }
- }
-
- if (show_details) {
- if (s.uid)
- printf(" uid=%u", (unsigned)s.uid);
- printf(" ino=%u", s.ino);
- printf(" sk=%llx", s.sk);
- if (opt[0])
- printf(" opt:\"%s\"", opt);
- }
printf("\n");
-
return 0;
}
-
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")
{
FILE *fp = NULL;
+ if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
+ return 0;
+
dg_proto = RAW_PROTO;
if (f->families&(1<<AF_INET)) {
} while (0);
}
-
-struct unixstat
-{
- struct unixstat *next;
- int ino;
- int peer;
- char *peer_name;
- int rq;
- int wq;
- int state;
- int type;
- char *name;
-};
-
-
-
int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
SS_ESTABLISHED, SS_CLOSING };
+#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
-#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct unixstat))
-
-static void unix_list_free(struct unixstat *list)
+static void unix_list_free(struct sockstat *list)
{
while (list) {
- struct unixstat *s = list;
+ struct sockstat *s = list;
+ char *name = sock_addr_get_str(&s->local);
+
list = list->next;
- if (s->name)
- free(s->name);
+
+ if (name)
+ free(name);
free(s);
}
}
return netid;
}
-static bool unix_type_skip(struct unixstat *s, struct filter *f)
+static bool unix_type_skip(struct sockstat *s, struct filter *f)
{
if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
return true;
return false;
}
-static void unix_stats_print(struct unixstat *list, struct filter *f)
+static bool unix_use_proc(void)
+{
+ return getenv("PROC_NET_UNIX") || getenv("PROC_ROOT");
+}
+
+static void unix_stats_print(struct sockstat *list, struct filter *f)
{
- struct unixstat *s;
- char *peer;
+ struct sockstat *s;
+ char *local, *peer;
+ char *ctx_buf = NULL;
+ bool use_proc = unix_use_proc();
+ char port_name[30] = {};
for (s = list; s; s = s->next) {
- if (!(f->states & (1<<s->state)))
+ if (!(f->states & (1 << s->state)))
continue;
if (unix_type_skip(s, f))
continue;
- peer = "*";
- if (s->peer_name)
- peer = s->peer_name;
+ local = sock_addr_get_str(&s->local);
+ peer = "*";
+
+ if (s->rport && use_proc) {
+ struct sockstat *p;
- if (s->peer && !s->peer_name) {
- struct unixstat *p;
for (p = list; p; p = p->next) {
- if (s->peer == p->ino)
+ if (s->rport == p->lport)
break;
}
+
if (!p) {
peer = "?";
} else {
- peer = p->name ? : "*";
+ peer = sock_addr_get_str(&p->local);
+ peer = peer ? : "*";
}
}
- if (f->f) {
- struct tcpstat tst;
- tst.local.family = AF_UNIX;
- tst.remote.family = AF_UNIX;
- memcpy(tst.local.data, &s->name, sizeof(s->name));
+ if (use_proc && f->f) {
if (strcmp(peer, "*") == 0)
- memset(tst.remote.data, 0, sizeof(peer));
+ memset(s->remote.data, 0, sizeof(char *));
else
- memcpy(tst.remote.data, &peer, sizeof(peer));
- if (run_ssfilter(f->f, &tst) == 0)
+ sock_addr_set_str(&s->remote, &peer);
+
+ if (run_ssfilter(f->f, s) == 0)
continue;
}
- if (netid_width)
- printf("%-*s ", netid_width,
- unix_netid_name(s->type));
- if (state_width)
- printf("%-*s ", state_width, sstate_name[s->state]);
- printf("%-6d %-6d ", s->rq, s->wq);
- printf("%*s %-*d %*s %-*d",
- addr_width, s->name ? : "*", serv_width, s->ino,
- addr_width, peer, serv_width, s->peer);
- char *buf = NULL;
+ sock_state_print(s, unix_netid_name(s->type));
+
+ sock_addr_print(local ?: "*", " ",
+ int_to_str(s->lport, port_name), NULL);
+ sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
+ NULL);
if (show_proc_ctx || show_sock_ctx) {
- if (find_entry(s->ino, &buf,
+ if (find_entry(s->ino, &ctx_buf,
(show_proc_ctx & show_sock_ctx) ?
PROC_SOCK_CTX : PROC_CTX) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
+ printf(" users:(%s)", ctx_buf);
+ free(ctx_buf);
}
} else if (show_users) {
- if (find_entry(s->ino, &buf, USERS) > 0) {
- printf(" users:(%s)", buf);
- free(buf);
+ if (find_entry(s->ino, &ctx_buf, USERS) > 0) {
+ printf(" users:(%s)", ctx_buf);
+ free(ctx_buf);
}
}
printf("\n");
struct filter *f = (struct filter *)arg;
struct unix_diag_msg *r = NLMSG_DATA(nlh);
struct rtattr *tb[UNIX_DIAG_MAX+1];
- char name[128];
- struct unixstat stat = { .name = "*" , .peer_name = "*" };
+ char *name = NULL;
+ struct sockstat stat = {};
parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
stat.type = r->udiag_type;
stat.state = r->udiag_state;
- stat.ino = r->udiag_ino;
+ stat.ino = stat.lport = r->udiag_ino;
+ stat.local.family = stat.remote.family = AF_UNIX;
if (unix_type_skip(&stat, f))
return 0;
if (tb[UNIX_DIAG_NAME]) {
int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
+ name = malloc(len + 1);
memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0';
if (name[0] == '\0')
name[0] = '@';
- stat.name = &name[0];
+ sock_addr_set_str(&stat.local, &name);
}
if (tb[UNIX_DIAG_PEER])
- stat.peer = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
+ stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
+
+ if (f->f && run_ssfilter(f->f, &stat) == 0)
+ return 0;
unix_stats_print(&stat, f);
}
if (show_mem || show_details)
printf("\n");
+
+ if (name)
+ free(name);
return 0;
}
char name[128];
int newformat = 0;
int cnt;
- struct unixstat *list = NULL;
+ struct sockstat *list = NULL;
if (!filter_af_get(f, AF_UNIX))
return 0;
- if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
- && unix_show_netlink(f) == 0)
+ if (!unix_use_proc() && unix_show_netlink(f) == 0)
return 0;
if ((fp = net_unix_open()) == NULL)
cnt = 0;
while (fgets(buf, sizeof(buf)-1, fp)) {
- struct unixstat *u, **insp;
+ struct sockstat *u, **insp;
int flags;
if (!(u = malloc(sizeof(*u))))
break;
- u->name = NULL;
- u->peer_name = NULL;
if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
- &u->peer, &u->rq, &u->wq, &flags, &u->type,
+ &u->rport, &u->rq, &u->wq, &flags, &u->type,
&u->state, &u->ino, name) < 8)
name[0] = 0;
- if (flags&(1<<16)) {
+ u->lport = u->ino;
+ u->local.family = u->remote.family = AF_UNIX;
+
+ if (flags & (1 << 16)) {
u->state = SS_LISTEN;
} else {
u->state = unix_state_map[u->state-1];
- if (u->type == SOCK_DGRAM &&
- u->state == SS_CLOSE &&
- u->peer)
+ if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
u->state = SS_ESTABLISHED;
}
if (!newformat) {
- u->peer = 0;
+ u->rport = 0;
u->rq = 0;
u->wq = 0;
}
*insp = u;
if (name[0]) {
- if ((u->name = malloc(strlen(name)+1)) == NULL)
- break;
- strcpy(u->name, name);
+ char *tmp = strdup(name);
+ sock_addr_set_str(&u->local, &tmp);
}
if (++cnt > MAX_UNIX_REMEMBER) {
unix_stats_print(list, f);
return 0;
}
-struct pktstat {
- uint8_t type;
- uint16_t prot;
- uint32_t iface;
- int state;
- uint32_t rq;
- uid_t uid;
- ino_t ino;
-};
-
-static int packet_stats_print(struct pktstat *s, const struct filter *f)
+static int packet_stats_print(struct sockstat *s, const struct filter *f)
{
char *buf = NULL;
+ const char *addr, *port;
+ char ll_name[16];
if (f->f) {
- struct tcpstat tst;
- tst.local.family = AF_PACKET;
- tst.remote.family = AF_PACKET;
- tst.rport = 0;
- tst.lport = s->iface;
- tst.local.data[0] = s->prot;
- tst.remote.data[0] = 0;
- if (run_ssfilter(f->f, &tst) == 0)
+ s->local.family = AF_PACKET;
+ s->remote.family = AF_PACKET;
+ s->local.data[0] = s->prot;
+ if (run_ssfilter(f->f, s) == 0)
return 1;
}
- if (netid_width)
- printf("%-*s ", netid_width,
- s->type == SOCK_RAW ? "p_raw" : "p_dgr");
- if (state_width)
- printf("%-*s ", state_width, "UNCONN");
+ sock_state_print(s, s->type == SOCK_RAW ? "p_raw" : "p_dgr");
- printf("%-6d %-6d ", s->rq, 0);
- if (s->prot == 3) {
- printf("%*s:", addr_width, "*");
- } else {
- char tb[16];
- printf("%*s:", addr_width,
- ll_proto_n2a(htons(s->prot), tb, sizeof(tb)));
- }
- if (s->iface == 0) {
- printf("%-*s ", serv_width, "*");
- } else {
- printf("%-*s ", serv_width, xll_index_to_name(s->iface));
- }
+ if (s->prot == 3)
+ addr = "*";
+ else
+ addr = ll_proto_n2a(htons(s->prot), ll_name, sizeof(ll_name));
+
+ if (s->iface == 0)
+ port = "*";
+ else
+ port = xll_index_to_name(s->iface);
- printf("%*s*%-*s", addr_width, "", serv_width, "");
+ sock_addr_print(addr, ":", port, NULL);
+ sock_addr_print("", "*", "", NULL);
if (show_proc_ctx || show_sock_ctx) {
if (find_entry(s->ino, &buf,
}
}
+ if (show_details)
+ sock_details_print(s);
+
return 0;
}
const struct filter *f = arg;
struct packet_diag_msg *r = NLMSG_DATA(nlh);
struct rtattr *tb[PACKET_DIAG_MAX+1];
- struct pktstat stat = {};
+ struct sockstat stat = {};
parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
if (!tb[PACKET_DIAG_MEMINFO])
return -1;
- stat.type = r->pdiag_type;
- stat.prot = r->pdiag_num;
- stat.ino = r->pdiag_ino;
+ stat.type = r->pdiag_type;
+ stat.prot = r->pdiag_num;
+ stat.ino = r->pdiag_ino;
+ stat.state = SS_CLOSE;
+ stat.sk = cookie_sk_get(&r->pdiag_cookie[0]);
if (tb[PACKET_DIAG_MEMINFO]) {
__u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
if (tb[PACKET_DIAG_INFO]) {
struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
- stat.iface = pinfo->pdi_index;
+ stat.lport = stat.iface = pinfo->pdi_index;
}
+ if (tb[PACKET_DIAG_UID])
+ stat.uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
+
if (packet_stats_print(&stat, f))
return 0;
- if (show_details) {
- __u32 uid = 0;
-
- if (tb[PACKET_DIAG_UID])
- uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
-
- printf(" ino=%u uid=%u sk=", r->pdiag_ino, uid);
- if (r->pdiag_cookie[1] != 0)
- printf("%08x", r->pdiag_cookie[1]);
- printf("%08x", r->pdiag_cookie[0]);
- }
-
if (show_bpf && tb[PACKET_DIAG_FILTER]) {
struct sock_filter *fil =
RTA_DATA(tb[PACKET_DIAG_FILTER]);
static int packet_show_line(char *buf, const struct filter *f, int fam)
{
unsigned long long sk;
- struct pktstat stat = {};
+ struct sockstat stat = {};
int type, prot, iface, state, rq, uid, ino;
sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
stat.type = type;
stat.prot = prot;
- stat.iface = iface;
+ 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;
- if (show_details) {
- printf(" ino=%u uid=%u sk=%llx", ino, uid, sk);
- }
printf("\n");
return 0;
}
return 0;
}
-static void netlink_show_one(struct filter *f,
+static int netlink_show_one(struct filter *f,
int prot, int pid, unsigned groups,
int state, int dst_pid, unsigned dst_group,
int rq, int wq,
unsigned long long sk, unsigned long long cb)
{
- SPRINT_BUF(prot_name);
+ struct sockstat st;
+ SPRINT_BUF(prot_buf) = {};
+ const char *prot_name;
+ char procname[64] = {};
+
+ st.state = SS_CLOSE;
+ st.rq = rq;
+ st.wq = wq;
if (f->f) {
- struct tcpstat tst;
- tst.local.family = AF_NETLINK;
- tst.remote.family = AF_NETLINK;
- tst.rport = -1;
- tst.lport = pid;
- tst.local.data[0] = prot;
- tst.remote.data[0] = 0;
- if (run_ssfilter(f->f, &tst) == 0)
- return;
+ st.local.family = AF_NETLINK;
+ st.remote.family = AF_NETLINK;
+ st.rport = -1;
+ st.lport = pid;
+ st.local.data[0] = prot;
+ if (run_ssfilter(f->f, &st) == 0)
+ return 1;
}
- if (netid_width)
- printf("%-*s ", netid_width, "nl");
- if (state_width)
- printf("%-*s ", state_width, "UNCONN");
- printf("%-6d %-6d ", rq, wq);
+ sock_state_print(&st, "nl");
- if (resolve_services) {
- printf("%*s:", addr_width, nl_proto_n2a(prot, prot_name,
- sizeof(prot_name)));
- } else {
- printf("%*d:", addr_width, prot);
- }
+ if (resolve_services)
+ prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
+ else
+ prot_name = int_to_str(prot, prot_buf);
if (pid == -1) {
- printf("%-*s ", serv_width, "*");
+ procname[0] = '*';
} else if (resolve_services) {
int done = 0;
if (!pid) {
done = 1;
- printf("%-*s ", serv_width, "kernel");
+ strncpy(procname, "kernel", 6);
} else if (pid > 0) {
- char procname[64];
FILE *fp;
sprintf(procname, "%s/%d/stat",
getenv("PROC_ROOT") ? : "/proc", pid);
if ((fp = fopen(procname, "r")) != NULL) {
if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
sprintf(procname+strlen(procname), "/%d", pid);
- printf("%-*s ", serv_width, procname);
done = 1;
}
fclose(fp);
}
}
if (!done)
- printf("%-*d ", serv_width, pid);
+ int_to_str(pid, procname);
} else {
- printf("%-*d ", serv_width, pid);
+ int_to_str(pid, procname);
}
+ sock_addr_print(prot_name, ":", procname, NULL);
+
if (state == NETLINK_CONNECTED) {
- printf("%*d:%-*d",
- addr_width, dst_group, serv_width, dst_pid);
+ char dst_group_buf[30];
+ char dst_pid_buf[30];
+ sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
+ int_to_str(dst_pid, dst_pid_buf), NULL);
} else {
- printf("%*s*%-*s",
- addr_width, "", serv_width, "");
+ sock_addr_print("", "*", "", NULL);
}
char *pid_context = NULL;
}
printf("\n");
- return;
+ return 0;
}
static int netlink_show_sock(const struct sockaddr_nl *addr,
wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
}
- netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
+ if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
- rq, wq, 0, 0);
+ rq, wq, 0, 0)) {
+ return 0;
+ }
if (show_mem) {
printf("\t");
/* Get stats from sockstat */
-struct sockstat
+struct ssummary
{
int socks;
int tcp_mem;
int frag6_mem;
};
-static void get_sockstat_line(char *line, struct sockstat *s)
+static void get_sockstat_line(char *line, struct ssummary *s)
{
char id[256], rem[256];
&s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
}
-static int get_sockstat(struct sockstat *s)
+static int get_sockstat(struct ssummary *s)
{
char buf[256];
FILE *fp;
static int print_summary(void)
{
- struct sockstat s;
+ struct ssummary s;
struct snmpstat sn;
if (get_sockstat(&s) < 0)
if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0)
perror("ss: get_snmpstat");
+ get_slabstat(&slabstat);
+
printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
" -b, --bpf show bpf filter socket information\n"
" -Z, --context display process SELinux security contexts\n"
" -z, --contexts display process and socket SELinux security contexts\n"
+" -N, --net switch to the specified network namespace name\n"
"\n"
" -4, --ipv4 display only IP version 4 sockets\n"
" -6, --ipv6 display only IP version 6 sockets\n"
{ "help", 0, 0, 'h' },
{ "context", 0, 0, 'Z' },
{ "contexts", 0, 0, 'z' },
+ { "net", 1, 0, 'N' },
{ 0 }
};
struct filter dbs_filter = {};
int state_filter = 0;
- while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZ",
+ while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZN:",
long_opts, NULL)) != EOF) {
switch(ch) {
case 'n':
show_proc_ctx++;
user_ent_hash_build();
break;
+ case 'N':
+ if (netns_switch(optarg))
+ exit(1);
+ break;
case 'h':
case '?':
help();
argc -= optind;
argv += optind;
- get_slabstat(&slabstat);
-
if (do_summary) {
print_summary();
if (do_default && argc == 0)
state_filter &= ~scan_state(*argv);
saw_states = 1;
} else {
- if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp))
- usage();
break;
}
argc--; argv++;
exit(0);
}
+ if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp))
+ usage();
+
netid_width = 0;
if (current_filter.dbs&(current_filter.dbs-1))
netid_width = 5;