Subject: [PATCH] inet: add bound ports statistic

From: Stephen Hemminger <[email-masked]>
Date: Wed, 28 Feb 2018 18:01:01 -0800

This adds a number of bound ports in a network namespace which is
a useful for socket summary (ss) command. It adds one additional
field onto /proc/net/sockstat.

Since collecting these kind of counters can be sensitive for large
machines, the impact is placed on the reading side which will be
much rarer.

Signed-off-by: Stephen Hemminger <[email-masked]>
---
 include/net/inet_connection_sock.h |  2 +-
 net/ipv4/inet_connection_sock.c    | 22 ++++++++++++++++++++++
 net/ipv4/proc.c                    |  5 +++--
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index c1a93ce35e62..3044deec73ce 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -265,7 +265,7 @@ inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
 }
 
 struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern);
-
+unsigned int inet_csk_count_ports(struct net *net, struct proto *prot);
 int inet_csk_get_port(struct sock *sk, unsigned short snum);
 
 struct dst_entry *inet_csk_route_req(const struct sock *sk, struct flowi4 *fl4,
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 881ac6d046f2..2418abce4d50 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -424,6 +424,28 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
 	return err;
 }
 
+/* Count how many any entries are in the bind hash table */
+unsigned int inet_csk_count_ports(struct net *net, struct proto *prot)
+{
+	struct inet_hashinfo *hinfo = prot->h.hashinfo;
+	struct inet_bind_hashbucket *head;
+	struct inet_bind_bucket *tb;
+	unsigned int i, ports = 0;
+
+	for (i = 0; i < hinfo->bhash_size; i++) {
+		head = &hinfo->bhash[i];
+
+		spin_lock_bh(&head->lock);
+		inet_bind_bucket_for_each(tb, &head->chain) {
+			if (net_eq(ib_net(tb), net))
+				++ports;
+		}
+		spin_unlock_bh(&head->lock);
+	}
+
+	return ports;
+}
+
 /*
  * This will accept the next outstanding connection.
  */
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index fdabc70283b6..7cd781026224 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -61,10 +61,11 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
 	sockets = proto_sockets_allocated_sum_positive(&tcp_prot);
 
 	socket_seq_show(seq);
-	seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld\n",
+	seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld ports %u\n",
 		   sock_prot_inuse_get(net, &tcp_prot), orphans,
 		   atomic_read(&net->ipv4.tcp_death_row.tw_count), sockets,
-		   proto_memory_allocated(&tcp_prot));
+		   proto_memory_allocated(&tcp_prot),
+		   inet_csk_count_ports(net, &tcp_prot));
 	seq_printf(seq, "UDP: inuse %d mem %ld\n",
 		   sock_prot_inuse_get(net, &udp_prot),
 		   proto_memory_allocated(&udp_prot));
-- 
2.16.1