]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - misc/ss.c
ss: Allow to specify sport/dport without ':'
[mirror_iproute2.git] / misc / ss.c
index 40dc1887007cedc56e532b2ecb3e0f712f474695..196b020cca77914e5df3470d06c7b3a6e4961508 100644 (file)
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -31,6 +31,7 @@
 #include "rt_names.h"
 #include "ll_map.h"
 #include "libnetlink.h"
+#include "namespace.h"
 #include "SNAPSHOT.h"
 
 #include <linux/tcp.h>
@@ -239,10 +240,11 @@ static void filter_db_set(struct filter *f, int db)
 
 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)
@@ -616,7 +618,7 @@ struct slabstat
        int skbs;
 };
 
-struct slabstat slabstat;
+static struct slabstat slabstat;
 
 static const char *slabstat_ids[] =
 {
@@ -632,6 +634,10 @@ static int get_slabstat(struct slabstat *s)
        char buf[256];
        FILE *fp;
        int cnt;
+       static int slabstat_valid;
+
+       if (slabstat_valid)
+               return 0;
 
        memset(s, 0, sizeof(*s));
 
@@ -655,10 +661,29 @@ static int get_slabstat(struct slabstat *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",
@@ -689,25 +714,106 @@ static const char *sstate_namel[] = {
        [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",
@@ -744,12 +850,6 @@ static const char *print_ms_timer(int timeout)
        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;
@@ -896,13 +996,12 @@ static const char *resolve_service(int port)
        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) {
@@ -919,14 +1018,14 @@ static void formatted_print(const inet_prefix *a, int port, unsigned int ifindex
                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
@@ -958,9 +1057,9 @@ static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
 
 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)
@@ -968,7 +1067,7 @@ static int unix_match(const inet_prefix *a, const inet_prefix *p)
        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:
@@ -976,8 +1075,7 @@ static int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
                 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);
                }
@@ -1282,30 +1380,27 @@ static int xll_name_to_index(const char *dev)
        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 = &current_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)
@@ -1331,7 +1426,7 @@ void *parse_hostcond(char *addr)
                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)
@@ -1357,12 +1452,14 @@ void *parse_hostcond(char *addr)
                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 [] */
@@ -1376,10 +1473,14 @@ void *parse_hostcond(char *addr)
        } 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;
@@ -1420,7 +1521,7 @@ void *parse_hostcond(char *addr)
                        }
                }
        }
-       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);
@@ -1430,8 +1531,11 @@ void *parse_hostcond(char *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)
@@ -1439,136 +1543,261 @@ out:
        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;
 }
 
@@ -1598,23 +1827,27 @@ outerr:
        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",
@@ -1633,23 +1866,17 @@ static void print_skmeminfo(struct rtattr *tb[], int attrtype)
        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;
@@ -1664,39 +1891,49 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
                        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]) {
@@ -1704,165 +1941,104 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
                                = 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;
 }
 
@@ -2109,6 +2285,9 @@ static int tcp_show(struct filter *f, int socktype)
        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"))
@@ -2128,6 +2307,8 @@ static int tcp_show(struct filter *f, int socktype)
         * 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;
@@ -2183,53 +2364,19 @@ outerr:
 
 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;
@@ -2243,50 +2390,22 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
        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")
@@ -2323,6 +2442,9 @@ 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 (f->families&(1<<AF_INET)) {
@@ -2351,35 +2473,21 @@ outerr:
        } 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);
        }
 }
@@ -2403,7 +2511,7 @@ static const char *unix_netid_name(int type)
        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;
@@ -2414,69 +2522,72 @@ static bool unix_type_skip(struct unixstat *s, struct filter *f)
        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");
@@ -2489,15 +2600,16 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
        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;
@@ -2510,14 +2622,18 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
        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);
 
@@ -2534,6 +2650,9 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
        }
        if (show_mem || show_details)
                printf("\n");
+
+       if (name)
+               free(name);
        return 0;
 }
 
@@ -2580,13 +2699,12 @@ static int unix_show(struct filter *f)
        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)
@@ -2598,31 +2716,30 @@ static int unix_show(struct filter *f)
        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;
                }
@@ -2639,9 +2756,8 @@ static int unix_show(struct filter *f)
                *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);
@@ -2661,53 +2777,34 @@ static int unix_show(struct filter *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,
@@ -2723,6 +2820,9 @@ static int packet_stats_print(struct pktstat *s, const struct filter *f)
                }
        }
 
+       if (show_details)
+               sock_details_print(s);
+
        return 0;
 }
 
@@ -2732,7 +2832,7 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
        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)));
@@ -2741,9 +2841,11 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
        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]);
@@ -2752,24 +2854,15 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
 
        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]);
@@ -2801,7 +2894,7 @@ static int packet_show_netlink(struct filter *f)
 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",
@@ -2816,17 +2909,16 @@ static int packet_show_line(char *buf, const struct filter *f, int fam)
 
        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;
 }
@@ -2850,72 +2942,72 @@ static int packet_show(struct filter *f)
        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;
@@ -2944,7 +3036,7 @@ static void netlink_show_one(struct filter *f,
        }
        printf("\n");
 
-       return;
+       return 0;
 }
 
 static int netlink_show_sock(const struct sockaddr_nl *addr,
@@ -2970,9 +3062,11 @@ 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");
@@ -3077,7 +3171,7 @@ static int get_snmp_int(char *proto, char *key, int *result)
 
 /* Get stats from sockstat */
 
-struct sockstat
+struct ssummary
 {
        int socks;
        int tcp_mem;
@@ -3096,7 +3190,7 @@ struct sockstat
        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];
 
@@ -3125,7 +3219,7 @@ static void get_sockstat_line(char *line, struct sockstat *s)
                       &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;
@@ -3149,7 +3243,7 @@ static int get_sockstat(struct sockstat *s)
 
 static int print_summary(void)
 {
-       struct sockstat s;
+       struct ssummary s;
        struct snmpstat sn;
 
        if (get_sockstat(&s) < 0)
@@ -3157,6 +3251,8 @@ static int print_summary(void)
        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",
@@ -3207,6 +3303,7 @@ static void _usage(FILE *dest)
 "   -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"
@@ -3306,6 +3403,7 @@ static const struct option long_opts[] = {
        { "help", 0, 0, 'h' },
        { "context", 0, 0, 'Z' },
        { "contexts", 0, 0, 'z' },
+       { "net", 1, 0, 'N' },
        { 0 }
 
 };
@@ -3321,7 +3419,7 @@ int main(int argc, char *argv[])
        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':
@@ -3493,6 +3591,10 @@ int main(int argc, char *argv[])
                        show_proc_ctx++;
                        user_ent_hash_build();
                        break;
+               case 'N':
+                       if (netns_switch(optarg))
+                               exit(1);
+                       break;
                case 'h':
                case '?':
                        help();
@@ -3504,8 +3606,6 @@ int main(int argc, char *argv[])
        argc -= optind;
        argv += optind;
 
-       get_slabstat(&slabstat);
-
        if (do_summary) {
                print_summary();
                if (do_default && argc == 0)
@@ -3533,8 +3633,6 @@ int main(int argc, char *argv[])
                        state_filter &= ~scan_state(*argv);
                        saw_states = 1;
                } else {
-                       if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
-                               usage();
                        break;
                }
                argc--; argv++;
@@ -3584,6 +3682,9 @@ int main(int argc, char *argv[])
                exit(0);
        }
 
+       if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
+               usage();
+
        netid_width = 0;
        if (current_filter.dbs&(current_filter.dbs-1))
                netid_width = 5;