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 <step...@networkplumber.org>
---
 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

Reply via email to