]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ss: Include -E option for socket destroy events
authorCraig Gallek <kraig@google.com>
Wed, 17 Jun 2015 15:14:48 +0000 (11:14 -0400)
committerStephen Hemminger <shemming@brocade.com>
Fri, 26 Jun 2015 04:13:47 +0000 (00:13 -0400)
Use the IPv4/IPv6/TCP/UDP multicast groups of NETLINK_SOCK_DIAG
to filter and display socket statistics as they are destroyed.

Kernel support patch series: 24029a3603cfa633e8bc2b3fb3e48e76c497831d

Signed-off-by: Craig Gallek <kraig@google.com>
misc/ss.c

index 78dfd5649c4f8d7839b8ecd0f551e8704c882d7c..d22528de1bfc6196b75d77f2f07e3a255a7ab88a 100644 (file)
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -99,6 +99,7 @@ int show_proc_ctx = 0;
 int show_sock_ctx = 0;
 /* If show_users & show_proc_ctx only do user_ent_hash_build() once */
 int user_ent_hash_build_init = 0;
+int follow_events = 0;
 
 int netid_width;
 int state_width;
@@ -2028,6 +2029,9 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
        if (f && f->f && run_ssfilter(f->f, &s) == 0)
                return 0;
 
+       if (tb[INET_DIAG_PROTOCOL])
+               protocol = *(__u8 *)RTA_DATA(tb[INET_DIAG_PROTOCOL]);
+
        inet_stats_print(&s, protocol);
 
        if (show_options) {
@@ -2199,7 +2203,7 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr,
 
        if (!(diag_arg->f->families & (1 << r->idiag_family)))
                return 0;
-       if ((err = inet_show_sock(h, NULL, diag_arg->protocol)) < 0)
+       if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0)
                return err;
 
        return 0;
@@ -3217,6 +3221,64 @@ static int netlink_show(struct filter *f)
        return 0;
 }
 
+struct sock_diag_msg {
+       __u8 sdiag_family;
+};
+
+static int generic_show_sock(const struct sockaddr_nl *addr,
+               struct nlmsghdr *nlh, void *arg)
+{
+       struct sock_diag_msg *r = NLMSG_DATA(nlh);
+       struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
+
+       switch (r->sdiag_family) {
+       case AF_INET:
+       case AF_INET6:
+               return show_one_inet_sock(addr, nlh, &inet_arg);
+       case AF_UNIX:
+               return unix_show_sock(addr, nlh, arg);
+       case AF_PACKET:
+               return packet_show_sock(addr, nlh, arg);
+       case AF_NETLINK:
+               return netlink_show_sock(addr, nlh, arg);
+       default:
+               return -1;
+       }
+}
+
+static int handle_follow_request(struct filter *f)
+{
+       int ret = -1;
+       int groups = 0;
+       struct rtnl_handle rth;
+
+       if (f->families & (1 << AF_INET) && f->dbs & (1 << TCP_DB))
+               groups |= 1 << (SKNLGRP_INET_TCP_DESTROY - 1);
+       if (f->families & (1 << AF_INET) && f->dbs & (1 << UDP_DB))
+               groups |= 1 << (SKNLGRP_INET_UDP_DESTROY - 1);
+       if (f->families & (1 << AF_INET6) && f->dbs & (1 << TCP_DB))
+               groups |= 1 << (SKNLGRP_INET6_TCP_DESTROY - 1);
+       if (f->families & (1 << AF_INET6) && f->dbs & (1 << UDP_DB))
+               groups |= 1 << (SKNLGRP_INET6_UDP_DESTROY - 1);
+
+       if (groups == 0)
+               return -1;
+
+       if (rtnl_open_byproto(&rth, groups, NETLINK_SOCK_DIAG))
+               return -1;
+
+       rth.dump = 0;
+       rth.local.nl_pid = 0;
+
+       if (rtnl_dump_filter(&rth, generic_show_sock, f))
+               goto Exit;
+
+       ret = 0;
+Exit:
+       rtnl_close(&rth);
+       return ret;
+}
+
 struct snmpstat
 {
        int tcp_estab;
@@ -3399,6 +3461,7 @@ static void _usage(FILE *dest)
 "   -i, --info          show internal TCP information\n"
 "   -s, --summary       show socket usage summary\n"
 "   -b, --bpf           show bpf filter socket information\n"
+"   -E, --events        continually display sockets as they are destroyed\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"
@@ -3481,6 +3544,7 @@ static const struct option long_opts[] = {
        { "info", 0, 0, 'i' },
        { "processes", 0, 0, 'p' },
        { "bpf", 0, 0, 'b' },
+       { "events", 0, 0, 'E' },
        { "dccp", 0, 0, 'd' },
        { "tcp", 0, 0, 't' },
        { "udp", 0, 0, 'u' },
@@ -3516,7 +3580,7 @@ int main(int argc, char *argv[])
        int ch;
        int state_filter = 0;
 
-       while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZN:",
+       while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:",
                                 long_opts, NULL)) != EOF) {
                switch(ch) {
                case 'n':
@@ -3546,6 +3610,9 @@ int main(int argc, char *argv[])
                        show_options = 1;
                        show_bpf++;
                        break;
+               case 'E':
+                       follow_events = 1;
+                       break;
                case 'd':
                        filter_db_set(&current_filter, DCCP_DB);
                        break;
@@ -3838,6 +3905,9 @@ int main(int argc, char *argv[])
 
        fflush(stdout);
 
+       if (follow_events)
+               exit(handle_follow_request(&current_filter));
+
        if (current_filter.dbs & (1<<NETLINK_DB))
                netlink_show(&current_filter);
        if (current_filter.dbs & PACKET_DBM)