netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option
@ 2022-05-25  2:51 Peilin Ye
  2022-05-25  2:51 ` [PATCH iproute2-next 1/7] ss: Use assignment-suppression character in sscanf() Peilin Ye
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:51 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

Hi all,

This patchset adds a new ss option, -T (--threads), to show thread
information.  It extends the -p (--processes) option, and should be useful
for debugging, monitoring multi-threaded applications.  Example output:

  $ ss -ltT "sport = 1234"
  State   Recv-Q  Send-Q  Local Address:Port      Peer Address:Port       Process
  LISTEN  0       100           0.0.0.0:1234           0.0.0.0:*           users:(("test",pid=2932547,tid=2932548,fd=3),("test",pid=2932547,tid=2932547,fd=3))

It implies -p i.e. it outputs all threads in the thread group, including
the thread group leader.  When -T is used, -Z and -z also show SELinux
contexts for threads.

[1-5/7] are small clean-ups for the user_ent_hash_build() function.  [6/7]
factors out logic iterating $PROC_ROOT/$PID/fd/ from user_ent_hash_build()
to make [7/7] easier.  [7/7] actually implements the feature.

Thanks,
Peilin Ye (7):
  ss: Use assignment-suppression character in sscanf()
  ss: Remove unnecessary stack variable 'p' in user_ent_hash_build()
  ss: Do not call user_ent_hash_build() more than once
  ss: Delete unnecessary call to snprintf() in user_ent_hash_build()
  ss: Fix coding style issues in user_ent_hash_build()
  ss: Factor out fd iterating logic from user_ent_hash_build()
  ss: Introduce -T, --threads option

 man/man8/ss.8 |   8 +-
 misc/ss.c     | 230 +++++++++++++++++++++++++++++---------------------
 2 files changed, 142 insertions(+), 96 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 1/7] ss: Use assignment-suppression character in sscanf()
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
@ 2022-05-25  2:51 ` Peilin Ye
  2022-05-25  2:52 ` [PATCH iproute2-next 2/7] ss: Remove unnecessary stack variable 'p' in user_ent_hash_build() Peilin Ye
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:51 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

Use the '*' assignment-suppression character, instead of an
inappropriately named temporary variable.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 4b3ca9c4e86b..aa9da7e45e53 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -621,9 +621,8 @@ static void user_ent_hash_build(void)
 		char *p;
 		int pid, pos;
 		DIR *dir1;
-		char crap;
 
-		if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
+		if (sscanf(d->d_name, "%d%*c", &pid) != 1)
 			continue;
 
 		if (getpidcon(pid, &pid_context) != 0)
@@ -647,7 +646,7 @@ static void user_ent_hash_build(void)
 			ssize_t link_len;
 			char tmp[1024];
 
-			if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
+			if (sscanf(d1->d_name, "%d%*c", &fd) != 1)
 				continue;
 
 			snprintf(name+pos, sizeof(name) - pos, "%d", fd);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 2/7] ss: Remove unnecessary stack variable 'p' in user_ent_hash_build()
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
  2022-05-25  2:51 ` [PATCH iproute2-next 1/7] ss: Use assignment-suppression character in sscanf() Peilin Ye
@ 2022-05-25  2:52 ` Peilin Ye
  2022-05-25  2:52 ` [PATCH iproute2-next 3/7] ss: Do not call user_ent_hash_build() more than once Peilin Ye
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:52 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

Commit 116ac9270b6d ("ss: Add support for retrieving SELinux contexts")
added an unnecessary stack variable, 'char *p', in
user_ent_hash_build().  Delete it for readability.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index aa9da7e45e53..bccf01bb5efa 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -618,7 +618,6 @@ static void user_ent_hash_build(void)
 	while ((d = readdir(dir)) != NULL) {
 		struct dirent *d1;
 		char process[16];
-		char *p;
 		int pid, pos;
 		DIR *dir1;
 
@@ -636,7 +635,6 @@ static void user_ent_hash_build(void)
 		}
 
 		process[0] = '\0';
-		p = process;
 
 		while ((d1 = readdir(dir1)) != NULL) {
 			const char *pattern = "socket:[";
@@ -667,18 +665,18 @@ static void user_ent_hash_build(void)
 			if (getfilecon(tmp, &sock_context) <= 0)
 				sock_context = strdup(no_ctx);
 
-			if (*p == '\0') {
+			if (process[0] == '\0') {
 				FILE *fp;
 
 				snprintf(tmp, sizeof(tmp), "%s/%d/stat",
 					root, pid);
 				if ((fp = fopen(tmp, "r")) != NULL) {
-					if (fscanf(fp, "%*d (%[^)])", p) < 1)
+					if (fscanf(fp, "%*d (%[^)])", process) < 1)
 						; /* ignore */
 					fclose(fp);
 				}
 			}
-			user_ent_add(ino, p, pid, fd,
+			user_ent_add(ino, process, pid, fd,
 					pid_context, sock_context);
 			freecon(sock_context);
 		}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 3/7] ss: Do not call user_ent_hash_build() more than once
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
  2022-05-25  2:51 ` [PATCH iproute2-next 1/7] ss: Use assignment-suppression character in sscanf() Peilin Ye
  2022-05-25  2:52 ` [PATCH iproute2-next 2/7] ss: Remove unnecessary stack variable 'p' in user_ent_hash_build() Peilin Ye
@ 2022-05-25  2:52 ` Peilin Ye
  2022-05-25  2:52 ` [PATCH iproute2-next 4/7] ss: Delete unnecessary call to snprintf() in user_ent_hash_build() Peilin Ye
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:52 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

Call user_ent_hash_build() once after the getopt_long() loop if -p, -z
or -Z is used.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index bccf01bb5efa..dd7b67a76255 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -596,13 +596,6 @@ static void user_ent_hash_build(void)
 	char *pid_context;
 	char *sock_context;
 	const char *no_ctx = "unavailable";
-	static int user_ent_hash_build_init;
-
-	/* If show_users & show_proc_ctx set only do this once */
-	if (user_ent_hash_build_init != 0)
-		return;
-
-	user_ent_hash_build_init = 1;
 
 	strlcpy(name, root, sizeof(name));
 
@@ -5509,7 +5502,6 @@ int main(int argc, char *argv[])
 			break;
 		case 'p':
 			show_users++;
-			user_ent_hash_build();
 			break;
 		case 'b':
 			show_options = 1;
@@ -5644,7 +5636,6 @@ int main(int argc, char *argv[])
 				exit(1);
 			}
 			show_proc_ctx++;
-			user_ent_hash_build();
 			break;
 		case 'N':
 			if (netns_switch(optarg))
@@ -5679,6 +5670,9 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	if (show_users || show_proc_ctx || show_sock_ctx)
+		user_ent_hash_build();
+
 	argc -= optind;
 	argv += optind;
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 4/7] ss: Delete unnecessary call to snprintf() in user_ent_hash_build()
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
                   ` (2 preceding siblings ...)
  2022-05-25  2:52 ` [PATCH iproute2-next 3/7] ss: Do not call user_ent_hash_build() more than once Peilin Ye
@ 2022-05-25  2:52 ` Peilin Ye
  2022-05-25  2:53 ` [PATCH iproute2-next 5/7] ss: Fix coding style issues " Peilin Ye
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:52 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

'name' is already $PROC_ROOT/$PID/fd/$FD there, no need to rebuild the
string.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index dd7b67a76255..ec14d746c669 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -652,10 +652,7 @@ static void user_ent_hash_build(void)
 
 			sscanf(lnk, "socket:[%u]", &ino);
 
-			snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
-					root, pid, d1->d_name);
-
-			if (getfilecon(tmp, &sock_context) <= 0)
+			if (getfilecon(name, &sock_context) <= 0)
 				sock_context = strdup(no_ctx);
 
 			if (process[0] == '\0') {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 5/7] ss: Fix coding style issues in user_ent_hash_build()
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
                   ` (3 preceding siblings ...)
  2022-05-25  2:52 ` [PATCH iproute2-next 4/7] ss: Delete unnecessary call to snprintf() in user_ent_hash_build() Peilin Ye
@ 2022-05-25  2:53 ` Peilin Ye
  2022-05-25  2:53 ` [PATCH iproute2-next 6/7] ss: Factor out fd iterating logic from user_ent_hash_build() Peilin Ye
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:53 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

Make checkpatch.pl --strict happy about user_ent_hash_build().

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index ec14d746c669..42d04bf432eb 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -599,7 +599,7 @@ static void user_ent_hash_build(void)
 
 	strlcpy(name, root, sizeof(name));
 
-	if (strlen(name) == 0 || name[strlen(name)-1] != '/')
+	if (strlen(name) == 0 || name[strlen(name) - 1] != '/')
 		strcat(name, "/");
 
 	nameoff = strlen(name);
@@ -622,7 +622,8 @@ static void user_ent_hash_build(void)
 
 		snprintf(name + nameoff, sizeof(name) - nameoff, "%d/fd/", pid);
 		pos = strlen(name);
-		if ((dir1 = opendir(name)) == NULL) {
+		dir1 = opendir(name);
+		if (!dir1) {
 			freecon(pid_context);
 			continue;
 		}
@@ -640,9 +641,9 @@ static void user_ent_hash_build(void)
 			if (sscanf(d1->d_name, "%d%*c", &fd) != 1)
 				continue;
 
-			snprintf(name+pos, sizeof(name) - pos, "%d", fd);
+			snprintf(name + pos, sizeof(name) - pos, "%d", fd);
 
-			link_len = readlink(name, lnk, sizeof(lnk)-1);
+			link_len = readlink(name, lnk, sizeof(lnk) - 1);
 			if (link_len == -1)
 				continue;
 			lnk[link_len] = '\0';
@@ -650,7 +651,8 @@ static void user_ent_hash_build(void)
 			if (strncmp(lnk, pattern, strlen(pattern)))
 				continue;
 
-			sscanf(lnk, "socket:[%u]", &ino);
+			if (sscanf(lnk, "socket:[%u]", &ino) != 1)
+				continue;
 
 			if (getfilecon(name, &sock_context) <= 0)
 				sock_context = strdup(no_ctx);
@@ -658,16 +660,16 @@ static void user_ent_hash_build(void)
 			if (process[0] == '\0') {
 				FILE *fp;
 
-				snprintf(tmp, sizeof(tmp), "%s/%d/stat",
-					root, pid);
-				if ((fp = fopen(tmp, "r")) != NULL) {
+				snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
+
+				fp = fopen(tmp, "r");
+				if (fp) {
 					if (fscanf(fp, "%*d (%[^)])", process) < 1)
 						; /* ignore */
 					fclose(fp);
 				}
 			}
-			user_ent_add(ino, process, pid, fd,
-					pid_context, sock_context);
+			user_ent_add(ino, process, pid, fd, pid_context, sock_context);
 			freecon(sock_context);
 		}
 		freecon(pid_context);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 6/7] ss: Factor out fd iterating logic from user_ent_hash_build()
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
                   ` (4 preceding siblings ...)
  2022-05-25  2:53 ` [PATCH iproute2-next 5/7] ss: Fix coding style issues " Peilin Ye
@ 2022-05-25  2:53 ` Peilin Ye
  2022-05-25  2:53 ` [PATCH iproute2-next 7/7] ss: Introduce -T, --threads option Peilin Ye
  2022-05-30 16:00 ` [PATCH iproute2-next 0/7] " patchwork-bot+netdevbpf
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:53 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

We are planning to add a thread version of the -p, --process option.
Move the logic iterating $PROC_ROOT/$PID/fd/ into a new function,
user_ent_hash_build_task(), to make it easier.

Since we will use this function for both processes and threads, rename
local variables as such (e.g. from "process" to "task").

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 misc/ss.c | 144 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 79 insertions(+), 65 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 42d04bf432eb..07d0057b22cc 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -567,6 +567,81 @@ static void user_ent_add(unsigned int ino, char *process,
 	*pp = p;
 }
 
+#define MAX_PATH_LEN	1024
+
+static void user_ent_hash_build_task(char *path, int pid)
+{
+	const char *no_ctx = "unavailable";
+	char task[16] = {'\0', };
+	char stat[MAX_PATH_LEN];
+	int pos_id, pos_fd;
+	char *task_context;
+	struct dirent *d;
+	DIR *dir;
+
+	if (getpidcon(pid, &task_context) != 0)
+		task_context = strdup(no_ctx);
+
+	pos_id = strlen(path);	/* $PROC_ROOT/$ID/ */
+
+	snprintf(path + pos_id, MAX_PATH_LEN - pos_id, "fd/");
+	dir = opendir(path);
+	if (!dir) {
+		freecon(task_context);
+		return;
+	}
+
+	pos_fd = strlen(path);	/* $PROC_ROOT/$ID/fd/ */
+
+	while ((d = readdir(dir)) != NULL) {
+		const char *pattern = "socket:[";
+		char *sock_context;
+		unsigned int ino;
+		ssize_t link_len;
+		char lnk[64];
+		int fd;
+
+		if (sscanf(d->d_name, "%d%*c", &fd) != 1)
+			continue;
+
+		snprintf(path + pos_fd, MAX_PATH_LEN - pos_fd, "%d", fd);
+
+		link_len = readlink(path, lnk, sizeof(lnk) - 1);
+		if (link_len == -1)
+			continue;
+		lnk[link_len] = '\0';
+
+		if (strncmp(lnk, pattern, strlen(pattern)))
+			continue;
+
+		if (sscanf(lnk, "socket:[%u]", &ino) != 1)
+			continue;
+
+		if (getfilecon(path, &sock_context) <= 0)
+			sock_context = strdup(no_ctx);
+
+		if (task[0] == '\0') {
+			FILE *fp;
+
+			strlcpy(stat, path, pos_id + 1);
+			snprintf(stat + pos_id, sizeof(stat) - pos_id, "stat");
+
+			fp = fopen(stat, "r");
+			if (fp) {
+				if (fscanf(fp, "%*d (%[^)])", task) < 1)
+					; /* ignore */
+				fclose(fp);
+			}
+		}
+
+		user_ent_add(ino, task, pid, fd, task_context, sock_context);
+		freecon(sock_context);
+	}
+
+	freecon(task_context);
+	closedir(dir);
+}
+
 static void user_ent_destroy(void)
 {
 	struct user_ent *p, *p_next;
@@ -589,13 +664,10 @@ static void user_ent_destroy(void)
 static void user_ent_hash_build(void)
 {
 	const char *root = getenv("PROC_ROOT") ? : "/proc/";
+	char name[MAX_PATH_LEN];
 	struct dirent *d;
-	char name[1024];
 	int nameoff;
 	DIR *dir;
-	char *pid_context;
-	char *sock_context;
-	const char *no_ctx = "unavailable";
 
 	strlcpy(name, root, sizeof(name));
 
@@ -609,71 +681,13 @@ static void user_ent_hash_build(void)
 		return;
 
 	while ((d = readdir(dir)) != NULL) {
-		struct dirent *d1;
-		char process[16];
-		int pid, pos;
-		DIR *dir1;
+		int pid;
 
 		if (sscanf(d->d_name, "%d%*c", &pid) != 1)
 			continue;
 
-		if (getpidcon(pid, &pid_context) != 0)
-			pid_context = strdup(no_ctx);
-
-		snprintf(name + nameoff, sizeof(name) - nameoff, "%d/fd/", pid);
-		pos = strlen(name);
-		dir1 = opendir(name);
-		if (!dir1) {
-			freecon(pid_context);
-			continue;
-		}
-
-		process[0] = '\0';
-
-		while ((d1 = readdir(dir1)) != NULL) {
-			const char *pattern = "socket:[";
-			unsigned int ino;
-			char lnk[64];
-			int fd;
-			ssize_t link_len;
-			char tmp[1024];
-
-			if (sscanf(d1->d_name, "%d%*c", &fd) != 1)
-				continue;
-
-			snprintf(name + pos, sizeof(name) - pos, "%d", fd);
-
-			link_len = readlink(name, lnk, sizeof(lnk) - 1);
-			if (link_len == -1)
-				continue;
-			lnk[link_len] = '\0';
-
-			if (strncmp(lnk, pattern, strlen(pattern)))
-				continue;
-
-			if (sscanf(lnk, "socket:[%u]", &ino) != 1)
-				continue;
-
-			if (getfilecon(name, &sock_context) <= 0)
-				sock_context = strdup(no_ctx);
-
-			if (process[0] == '\0') {
-				FILE *fp;
-
-				snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
-
-				fp = fopen(tmp, "r");
-				if (fp) {
-					if (fscanf(fp, "%*d (%[^)])", process) < 1)
-						; /* ignore */
-					fclose(fp);
-				}
-			}
-			user_ent_add(ino, process, pid, fd, pid_context, sock_context);
-			freecon(sock_context);
-		}
-		freecon(pid_context);
-		closedir(dir1);
+		snprintf(name + nameoff, sizeof(name) - nameoff, "%d/", pid);
+		user_ent_hash_build_task(name, pid);
 	}
 	closedir(dir);
 }
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH iproute2-next 7/7] ss: Introduce -T, --threads option
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
                   ` (5 preceding siblings ...)
  2022-05-25  2:53 ` [PATCH iproute2-next 6/7] ss: Factor out fd iterating logic from user_ent_hash_build() Peilin Ye
@ 2022-05-25  2:53 ` Peilin Ye
  2022-05-30 16:00 ` [PATCH iproute2-next 0/7] " patchwork-bot+netdevbpf
  7 siblings, 0 replies; 9+ messages in thread
From: Peilin Ye @ 2022-05-25  2:53 UTC (permalink / raw)
  To: Stephen Hemminger, David Ahern, netdev
  Cc: Peilin Ye, Richard Haines, Cong Wang, Peilin Ye

From: Peilin Ye <peilin.ye@bytedance.com>

The -p, -Z and -z options only show process (thread group leader)
information.  For example, if the thread group leader has exited, but
another thread in the group is still using a socket, ss -[pZz] does not
show it.

Add a new option, -T (--threads), to show thread information.  It implies
the -p option.  For example, imagine process A and thread B (in the same
group) using the same socket.  ss -p only shows A:

  $ ss -ltp "sport = 1234"
  State   Recv-Q  Send-Q  Local Address:Port      Peer Address:Port       Process
  LISTEN  0       100           0.0.0.0:1234           0.0.0.0:*           users:(("test",pid=2932547,fd=3))

ss -T shows A and B:

  $ ss -ltT "sport = 1234"
  State   Recv-Q  Send-Q  Local Address:Port      Peer Address:Port       Process
  LISTEN  0       100           0.0.0.0:1234           0.0.0.0:*           users:(("test",pid=2932547,tid=2932548,fd=3),("test",pid=2932547,tid=2932547,fd=3))

If -T is used, -Z and -z also show SELinux contexts for threads.

Rename some variables (from "process" to "task", for example) since we
use them for both processes and threads.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
---
 man/man8/ss.8 |  8 ++++-
 misc/ss.c     | 94 +++++++++++++++++++++++++++++++++++----------------
 2 files changed, 72 insertions(+), 30 deletions(-)

diff --git a/man/man8/ss.8 b/man/man8/ss.8
index 68f0a699e61b..026530ed77bd 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -155,6 +155,10 @@ the number of packets dropped before they are de-multiplexed into the socket
 .B \-p, \-\-processes
 Show process using socket.
 .TP
+.B \-T, \-\-threads
+Show thread using socket. Implies \-p.
+.BR \-p .
+.TP
 .B \-i, \-\-info
 Show internal TCP information. Below fields may appear:
 .RS
@@ -311,7 +315,9 @@ Continually display sockets as they are destroyed
 .B \-Z, \-\-context
 As the
 .B \-p
-option but also shows process security context.
+option but also shows process security context. If the
+.B \-T
+option is used, also shows thread security context.
 .sp
 For
 .BR netlink (7)
diff --git a/misc/ss.c b/misc/ss.c
index 07d0057b22cc..344bb0f055d6 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -112,7 +112,8 @@ static void freecon(char *context)
 int preferred_family = AF_UNSPEC;
 static int show_options;
 int show_details;
-static int show_users;
+static int show_processes;
+static int show_threads;
 static int show_mem;
 static int show_tcpinfo;
 static int show_bpf;
@@ -526,9 +527,10 @@ struct user_ent {
 	struct user_ent	*next;
 	unsigned int	ino;
 	int		pid;
+	int		tid;
 	int		fd;
-	char		*process;
-	char		*process_ctx;
+	char		*task;
+	char		*task_ctx;
 	char		*socket_ctx;
 };
 
@@ -542,9 +544,9 @@ static int user_ent_hashfn(unsigned int ino)
 	return val & (USER_ENT_HASH_SIZE - 1);
 }
 
-static void user_ent_add(unsigned int ino, char *process,
-					int pid, int fd,
-					char *proc_ctx,
+static void user_ent_add(unsigned int ino, char *task,
+					int pid, int tid, int fd,
+					char *task_ctx,
 					char *sock_ctx)
 {
 	struct user_ent *p, **pp;
@@ -557,9 +559,10 @@ static void user_ent_add(unsigned int ino, char *process,
 	p->next = NULL;
 	p->ino = ino;
 	p->pid = pid;
+	p->tid = tid;
 	p->fd = fd;
-	p->process = strdup(process);
-	p->process_ctx = strdup(proc_ctx);
+	p->task = strdup(task);
+	p->task_ctx = strdup(task_ctx);
 	p->socket_ctx = strdup(sock_ctx);
 
 	pp = &user_ent_hash[user_ent_hashfn(ino)];
@@ -569,7 +572,7 @@ static void user_ent_add(unsigned int ino, char *process,
 
 #define MAX_PATH_LEN	1024
 
-static void user_ent_hash_build_task(char *path, int pid)
+static void user_ent_hash_build_task(char *path, int pid, int tid)
 {
 	const char *no_ctx = "unavailable";
 	char task[16] = {'\0', };
@@ -579,7 +582,7 @@ static void user_ent_hash_build_task(char *path, int pid)
 	struct dirent *d;
 	DIR *dir;
 
-	if (getpidcon(pid, &task_context) != 0)
+	if (getpidcon(tid, &task_context) != 0)
 		task_context = strdup(no_ctx);
 
 	pos_id = strlen(path);	/* $PROC_ROOT/$ID/ */
@@ -634,7 +637,7 @@ static void user_ent_hash_build_task(char *path, int pid)
 			}
 		}
 
-		user_ent_add(ino, task, pid, fd, task_context, sock_context);
+		user_ent_add(ino, task, pid, tid, fd, task_context, sock_context);
 		freecon(sock_context);
 	}
 
@@ -650,8 +653,8 @@ static void user_ent_destroy(void)
 	while (cnt != USER_ENT_HASH_SIZE) {
 		p = user_ent_hash[cnt];
 		while (p) {
-			free(p->process);
-			free(p->process_ctx);
+			free(p->task);
+			free(p->task_ctx);
 			free(p->socket_ctx);
 			p_next = p->next;
 			free(p);
@@ -687,7 +690,30 @@ static void user_ent_hash_build(void)
 			continue;
 
 		snprintf(name + nameoff, sizeof(name) - nameoff, "%d/", pid);
-		user_ent_hash_build_task(name, pid);
+		user_ent_hash_build_task(name, pid, pid);
+
+		if (show_threads) {
+			struct dirent *task_d;
+			DIR *task_dir;
+
+			snprintf(name + nameoff, sizeof(name) - nameoff, "%d/task/", pid);
+
+			task_dir = opendir(name);
+			if (!task_dir)
+				continue;
+
+			while ((task_d = readdir(task_dir)) != NULL) {
+				int tid;
+
+				if (sscanf(task_d->d_name, "%d%*c", &tid) != 1)
+					continue;
+				if (tid == pid)
+					continue;
+
+				snprintf(name + nameoff, sizeof(name) - nameoff, "%d/", tid);
+				user_ent_hash_build_task(name, pid, tid);
+			}
+		}
 	}
 	closedir(dir);
 }
@@ -704,6 +730,7 @@ static int find_entry(unsigned int ino, char **buf, int type)
 	struct user_ent *p;
 	int cnt = 0;
 	char *ptr;
+	char thread_info[16] = {'\0', };
 	char *new_buf;
 	int len, new_buf_len;
 	int buf_used = 0;
@@ -720,23 +747,27 @@ static int find_entry(unsigned int ino, char **buf, int type)
 
 		while (1) {
 			ptr = *buf + buf_used;
+
+			if (show_threads)
+				snprintf(thread_info, sizeof(thread_info), "tid=%d,", p->tid);
+
 			switch (type) {
 			case USERS:
 				len = snprintf(ptr, buf_len - buf_used,
-					"(\"%s\",pid=%d,fd=%d),",
-					p->process, p->pid, p->fd);
+					"(\"%s\",pid=%d,%sfd=%d),",
+					p->task, p->pid, thread_info, p->fd);
 				break;
 			case PROC_CTX:
 				len = snprintf(ptr, buf_len - buf_used,
-					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d),",
-					p->process, p->pid,
-					p->process_ctx, p->fd);
+					"(\"%s\",pid=%d,%sproc_ctx=%s,fd=%d),",
+					p->task, p->pid, thread_info,
+					p->task_ctx, p->fd);
 				break;
 			case PROC_SOCK_CTX:
 				len = snprintf(ptr, buf_len - buf_used,
-					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d,sock_ctx=%s),",
-					p->process, p->pid,
-					p->process_ctx, p->fd,
+					"(\"%s\",pid=%d,%sproc_ctx=%s,fd=%d,sock_ctx=%s),",
+					p->task, p->pid, thread_info,
+					p->task_ctx, p->fd,
 					p->socket_ctx);
 				break;
 			default:
@@ -2417,7 +2448,7 @@ static void proc_ctx_print(struct sockstat *s)
 			out(" users:(%s)", buf);
 			free(buf);
 		}
-	} else if (show_users) {
+	} else if (show_processes || show_threads) {
 		if (find_entry(s->ino, &buf, USERS) > 0) {
 			out(" users:(%s)", buf);
 			free(buf);
@@ -5312,6 +5343,7 @@ static void _usage(FILE *dest)
 "   -e, --extended      show detailed socket information\n"
 "   -m, --memory        show socket memory usage\n"
 "   -p, --processes     show process using socket\n"
+"   -T, --threads       show thread using socket\n"
 "   -i, --info          show internal TCP information\n"
 "       --tipcinfo      show internal tipc socket information\n"
 "   -s, --summary       show socket usage summary\n"
@@ -5319,8 +5351,8 @@ static void _usage(FILE *dest)
 "       --cgroup        show cgroup information\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"
+"   -Z, --context       display task SELinux security contexts\n"
+"   -z, --contexts      display task 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"
@@ -5441,6 +5473,7 @@ static const struct option long_opts[] = {
 	{ "memory", 0, 0, 'm' },
 	{ "info", 0, 0, 'i' },
 	{ "processes", 0, 0, 'p' },
+	{ "threads", 0, 0, 'T' },
 	{ "bpf", 0, 0, 'b' },
 	{ "events", 0, 0, 'E' },
 	{ "dccp", 0, 0, 'd' },
@@ -5491,7 +5524,7 @@ int main(int argc, char *argv[])
 	int state_filter = 0;
 
 	while ((ch = getopt_long(argc, argv,
-				 "dhaletuwxnro460spbEf:mMiA:D:F:vVzZN:KHSO",
+				 "dhaletuwxnro460spTbEf:mMiA:D:F:vVzZN:KHSO",
 				 long_opts, NULL)) != EOF) {
 		switch (ch) {
 		case 'n':
@@ -5514,7 +5547,10 @@ int main(int argc, char *argv[])
 			show_tcpinfo = 1;
 			break;
 		case 'p':
-			show_users++;
+			show_processes++;
+			break;
+		case 'T':
+			show_threads++;
 			break;
 		case 'b':
 			show_options = 1;
@@ -5683,7 +5719,7 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	if (show_users || show_proc_ctx || show_sock_ctx)
+	if (show_processes || show_threads || show_proc_ctx || show_sock_ctx)
 		user_ent_hash_build();
 
 	argc -= optind;
@@ -5803,7 +5839,7 @@ int main(int argc, char *argv[])
 	if (current_filter.dbs & (1<<MPTCP_DB))
 		mptcp_show(&current_filter);
 
-	if (show_users || show_proc_ctx || show_sock_ctx)
+	if (show_processes || show_threads || show_proc_ctx || show_sock_ctx)
 		user_ent_destroy();
 
 	render();
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option
  2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
                   ` (6 preceding siblings ...)
  2022-05-25  2:53 ` [PATCH iproute2-next 7/7] ss: Introduce -T, --threads option Peilin Ye
@ 2022-05-30 16:00 ` patchwork-bot+netdevbpf
  7 siblings, 0 replies; 9+ messages in thread
From: patchwork-bot+netdevbpf @ 2022-05-30 16:00 UTC (permalink / raw)
  To: Peilin Ye
  Cc: stephen, dsahern, netdev, peilin.ye, richard_c_haines, cong.wang

Hello:

This series was applied to iproute2/iproute2-next.git (main)
by David Ahern <dsahern@kernel.org>:

On Tue, 24 May 2022 19:51:15 -0700 you wrote:
> From: Peilin Ye <peilin.ye@bytedance.com>
> 
> Hi all,
> 
> This patchset adds a new ss option, -T (--threads), to show thread
> information.  It extends the -p (--processes) option, and should be useful
> for debugging, monitoring multi-threaded applications.  Example output:
> 
> [...]

Here is the summary with links:
  - [iproute2-next,1/7] ss: Use assignment-suppression character in sscanf()
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=2d866c6d93db
  - [iproute2-next,2/7] ss: Remove unnecessary stack variable 'p' in user_ent_hash_build()
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=b38831bc23c4
  - [iproute2-next,3/7] ss: Do not call user_ent_hash_build() more than once
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=cd845a85681b
  - [iproute2-next,4/7] ss: Delete unnecessary call to snprintf() in user_ent_hash_build()
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=ea3b57ec3991
  - [iproute2-next,5/7] ss: Fix coding style issues in user_ent_hash_build()
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=210018bfe99b
  - [iproute2-next,6/7] ss: Factor out fd iterating logic from user_ent_hash_build()
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=12d491e58ff5
  - [iproute2-next,7/7] ss: Introduce -T, --threads option
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=e2267e68b9b5

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-05-30 16:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-25  2:51 [PATCH iproute2-next 0/7] ss: Introduce -T, --threads option Peilin Ye
2022-05-25  2:51 ` [PATCH iproute2-next 1/7] ss: Use assignment-suppression character in sscanf() Peilin Ye
2022-05-25  2:52 ` [PATCH iproute2-next 2/7] ss: Remove unnecessary stack variable 'p' in user_ent_hash_build() Peilin Ye
2022-05-25  2:52 ` [PATCH iproute2-next 3/7] ss: Do not call user_ent_hash_build() more than once Peilin Ye
2022-05-25  2:52 ` [PATCH iproute2-next 4/7] ss: Delete unnecessary call to snprintf() in user_ent_hash_build() Peilin Ye
2022-05-25  2:53 ` [PATCH iproute2-next 5/7] ss: Fix coding style issues " Peilin Ye
2022-05-25  2:53 ` [PATCH iproute2-next 6/7] ss: Factor out fd iterating logic from user_ent_hash_build() Peilin Ye
2022-05-25  2:53 ` [PATCH iproute2-next 7/7] ss: Introduce -T, --threads option Peilin Ye
2022-05-30 16:00 ` [PATCH iproute2-next 0/7] " patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).