Skip to contentSkip to conversation

ss: Allow selection of columns to be displayed

PATCH In review Stefano Brivio 4 participants 14 messages Oct 30, 2018 – Nov 2, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover ss: Allow selection of columns to be displayed

Now that we have an abstraction for columns, it's relatively easy to selectively display only some of them, and Yoann has a use case for it.

Patch 1/3 fixes a rendering issue that shows up only when display of arbitrary columns is disabled. Patch 2/3 implements the relevant option, and patch 3/3 makes the output more readable when some columns are disabled.

Stefano Brivio (3):
ss: Discard empty descriptor at the end of buffer, if any, before
rendering
ss: Introduce option to display selected columns only
ss: Beautify output when arbitrary columns are hidden

 man/man8/ss.8 |  5 +++
 misc/ss.c     | 85 +++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 77 insertions(+), 13 deletions(-)
Signature · 1 line
2.19.1
#1 lore raw

PATCH 1/3 ss: Discard empty descriptor at the end of buffer, if any, before rendering

This will allow us to disable display of any given column.

---
 misc/ss.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
misc/ss.c +9 -2
index c8970438ce73..c3f61ef66258 100644
@@ -1245,8 +1245,15 @@ static void render(void)
 
 	token = (struct buf_token *)buffer.head->data;
 
-	/* Ensure end alignment of last token, it wasn't necessarily flushed */
-	buffer.tail->end += buffer.cur->len % 2;
+	if (!buffer.cur->len) {
+		/* Last token was flushed, a new empty descriptor was appended:
+		 * discard it
+		 */
+		buffer.tail->end -= sizeof(buffer.cur->len);
+	} else {
+		/* Last token wasn't flushed: ensure end alignment */
+		buffer.tail->end += buffer.cur->len % 2;
+	}
 
 	render_calc_width();
 
Signature · 1 line
2.19.1
#2 lore raw

PATCH 2/3 ss: Introduce option to display selected columns only

In reply to Stefano Brivio

The new option --columns (short: -c) allows to select columns to be displayed. Note that this doesn't affect the order in which columns are displayed.

---
 man/man8/ss.8 |  5 +++++
 misc/ss.c     | 62 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 57 insertions(+), 10 deletions(-)
man/man8/ss.8 +5 -0
index 7a6572b17364..c987dec6bcd7 100644
@@ -24,6 +24,11 @@ Output version information.
 .B \-H, \-\-no-header
 Suppress header line.
 .TP
+.B \-c COLS, \-\-columns=COLS
+Only display selected columns, separated by commas. The following column names
+are understood: netid, state, local, lport, peer, pport, ext. This does not
+define the order of columns.
+.TP
 .B \-n, \-\-numeric
 Do not try to resolve service names.
 .TP
misc/ss.c +52 -10

104 lines not on this page · raw message

Signature · 1 line
2.19.1
#3 lore raw

PATCH 3/3 ss: Beautify output when arbitrary columns are hidden

In reply to Stefano Brivio

Define a secondary alignment for columns in case the next column is hidden, this avoids awkward outputs if e.g. the local address is shown, but not the local port.

Omit embedded delimiter in socket specifiers if the port or service field is hidden.

---
 misc/ss.c | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)
misc/ss.c +20 -10
index 91be3c6db151..d489233681e9 100644
@@ -131,7 +131,8 @@ enum col_align {
 };
 
 struct column {
-	const enum col_align align;
+	enum col_align align;
+	const enum col_align align_without_next;
 	const char *optname;
 	const char *header;
 	const char *ldelim;
@@ -141,15 +142,15 @@ struct column {
 };
 
 static struct column columns[] = {
-	{ ALIGN_LEFT,	"netid",	"Netid",		"",  0, 0, 0 },
-	{ ALIGN_LEFT,	"state",	"State",		" ", 0, 0, 0 },
-	{ ALIGN_LEFT,	"recvq",	"Recv-Q",		" ", 0, 0, 0 },
-	{ ALIGN_LEFT,	"sendq",	"Send-Q",		" ", 0, 0, 0 },
-	{ ALIGN_RIGHT,	"local",	"Local Address:",	" ", 0, 0, 0 },
-	{ ALIGN_LEFT,	"lport",	"Port",			"",  0, 0, 0 },
-	{ ALIGN_RIGHT,	"peer",		"Peer Address:",	" ", 0, 0, 0 },
-	{ ALIGN_LEFT,	"pport",	"Port",			"",  0, 0, 0 },
-	{ ALIGN_LEFT,	"ext",		"",			"",  0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "netid", "Netid",          "",  0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "state", "State",          " ", 0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "recvq", "Recv-Q",         " ", 0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "sendq", "Send-Q",         " ", 0, 0, 0 },
+	{ ALIGN_RIGHT, ALIGN_LEFT, "local", "Local Address:", " ", 0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "lport", "Port",           "",  0, 0, 0 },
+	{ ALIGN_RIGHT, ALIGN_LEFT, "peer",  "Peer Address:",  " ", 0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "pport", "Port",           "",  0, 0, 0 },
+	{ ALIGN_LEFT,  ALIGN_LEFT, "ext",   "",               "",  0, 0, 0 },
 };
 
 static struct column *current_field = columns;
@@ -1374,6 +1375,9 @@ static void sock_details_print(struct sockstat *s)
 static void sock_addr_print(const char *addr, char *delim, const char *port,
 		const char *ifname)
 {
+	if ((current_field + 1)->disabled)
+		delim = "";
+
 	if (ifname)
 		out("%s" "%%" "%s%s", addr, ifname, delim);
 	else
@@ -5006,6 +5010,12 @@ int main(int argc, char *argv[])
 				}
 				p = p1 + 1;
 			} while (p1);
+
+			for (f = columns; field_is_valid(f + 1); f++) {
+				if ((f + 1)->disabled)
+					f->align = f->align_without_next;
+			}
+
 			break;
 		}
 		case 'h':
Signature · 1 line
2.19.1
#4 lore raw
In reply to Stefano Brivio
Quoted 9 lines · Stefano Brivio

Now that we have an abstraction for columns, it's relatively easy to selectively display only some of them, and Yoann has a use case for it.

Patch 1/3 fixes a rendering issue that shows up only when display of arbitrary columns is disabled. Patch 2/3 implements the relevant option, and patch 3/3 makes the output more readable when some columns are disabled.

I like the intent, and I have prototyped something similar for 'ip'.

A more flexible approach is to use format strings to allow users to customize the output order and whitespace as well. So for ss and your column list (winging it here):

    netid          = %N
    state          = %S
    recv Q         = %Qr
    send Q         = %Qs
    local address  = %Al
    lport port     = %Pl

remote address = %Ar
remote port = %Pr
process data = %p
...

then a format string could be: "%S %Qr %Qs %Al:%Pl %Ar:%Pr %p\n"

or for csv output: "%S,%Qr,%Qs,%Al,%Pl,%Ar,%Pr,%p\n"

I have not had time to look into an implementation for ip. Conceptually
- and scanning the kernel's vsprintf code - it does not look that difficult, just time consuming on the frontend with the initial setup.

#5 lore raw
Quoted 28 lines · On Tue, 30 Oct 2018 10:34:45 -0600 David Ahern <[email protected]> wrote:
Quoted 9 lines · Stefano Brivio

Now that we have an abstraction for columns, it's relatively easy to selectively display only some of them, and Yoann has a use case for it.

Patch 1/3 fixes a rendering issue that shows up only when display of arbitrary columns is disabled. Patch 2/3 implements the relevant option, and patch 3/3 makes the output more readable when some columns are disabled.

I like the intent, and I have prototyped something similar for 'ip'.

A more flexible approach is to use format strings to allow users to customize the output order and whitespace as well. So for ss and your column list (winging it here):

    netid          = %N
    state          = %S
    recv Q         = %Qr
    send Q         = %Qs
    local address  = %Al
    lport port     = %Pl

remote address = %Ar
remote port = %Pr
process data = %p
...

Quoted 7 lines

then a format string could be: "%S %Qr %Qs %Al:%Pl %Ar:%Pr %p\n"

or for csv output: "%S,%Qr,%Qs,%Al,%Pl,%Ar,%Pr,%p\n"

I have not had time to look into an implementation for ip. Conceptually
- and scanning the kernel's vsprintf code - it does not look that difficult, just time consuming on the frontend with the initial setup.

The problem with custom formats is that you lose all ability for Gcc to check format strings.

#6 lore raw
Quoted 33 lines · Stephen Hemminger
Quoted 30 lines · On Tue, 30 Oct 2018 10:34:45 -0600 David Ahern <[email protected]> wrote:
Quoted 9 lines · Stefano Brivio

Now that we have an abstraction for columns, it's relatively easy to selectively display only some of them, and Yoann has a use case for it.

Patch 1/3 fixes a rendering issue that shows up only when display of arbitrary columns is disabled. Patch 2/3 implements the relevant option, and patch 3/3 makes the output more readable when some columns are disabled.

I like the intent, and I have prototyped something similar for 'ip'.

A more flexible approach is to use format strings to allow users to customize the output order and whitespace as well. So for ss and your column list (winging it here):

    netid          = %N
    state          = %S
    recv Q         = %Qr
    send Q         = %Qs
    local address  = %Al
    lport port     = %Pl

remote address = %Ar
remote port = %Pr
process data = %p
...

then a format string could be: "%S %Qr %Qs %Al:%Pl %Ar:%Pr %p\n"

Quoted 9 lines
Quoted 5 lines

or for csv output: "%S,%Qr,%Qs,%Al,%Pl,%Ar,%Pr,%p\n"

I have not had time to look into an implementation for ip. Conceptually
- and scanning the kernel's vsprintf code - it does not look that difficult, just time consuming on the frontend with the initial setup.

The problem with custom formats is that you lose all ability for Gcc to check format strings.

Sure, trade-offs. A custom print string is powerful.

While selecting columns is an improvement, column ordering is also important - even handling other output formats (csv).

#7 lore raw
In reply to David Ahern
Quoted 10 lines · On Tue, 30 Oct 2018 10:34:45 -0600 David Ahern <[email protected]> wrote:

A more flexible approach is to use format strings to allow users to customize the output order and whitespace as well. So for ss and your column list (winging it here):

    netid          = %N
    state          = %S
    recv Q         = %Qr
    send Q         = %Qs
    local address  = %Al
    lport port     = %Pl
Quoted 6 lines

remote address = %Ar
remote port = %Pr
process data = %p
...

then a format string could be: "%S %Qr %Qs %Al:%Pl %Ar:%Pr %p\n"

I like the idea indeed, but I see two issues with ss:

- the current column abstraction is rather lightweight, things are already buffered in the defined column order so we don't have to jump back and forth in the buffer while rendering. Doing that needs some extra care to avoid a performance hit, but it's probably doable, I can put that on my to-do list

- how would you model automatic spacing in a format string? Should we support width specifiers? Disable automatic spacing if a format string is given? It might even make sense to allow partial automatic spacing with a special character in the format string, that is:

	"%S.%Qr.%Qs  %Al:%Pl %Ar:%Pr  %p\n"

would mean "align everything to the right, distribute remaining whitespace between %S, %Qr and %Qs". But it looks rather complicated at a glance.

Signature · 1 line
Stefano
#8 lore raw

[ sorry, too many distractions and I forgot to respond ]

Quoted 20 lines · Stefano Brivio
Quoted 10 lines · On Tue, 30 Oct 2018 10:34:45 -0600 David Ahern <[email protected]> wrote:

A more flexible approach is to use format strings to allow users to customize the output order and whitespace as well. So for ss and your column list (winging it here):

    netid          = %N
    state          = %S
    recv Q         = %Qr
    send Q         = %Qs
    local address  = %Al
    lport port     = %Pl
Quoted 6 lines

remote address = %Ar
remote port = %Pr
process data = %p
...

then a format string could be: "%S %Qr %Qs %Al:%Pl %Ar:%Pr %p\n"

Quoted 7 lines

I like the idea indeed, but I see two issues with ss:

- the current column abstraction is rather lightweight, things are already buffered in the defined column order so we don't have to jump back and forth in the buffer while rendering. Doing that needs some extra care to avoid a performance hit, but it's probably doable, I can put that on my to-do list

The ss command is always a pain; it's much better in newer releases but I am always having to adjust terminal width.

Quoted 4 lines

- how would you model automatic spacing in a format string? Should we support width specifiers? Disable automatic spacing if a format string is given? It might even make sense to allow partial automatic

Follow the format string for whitespace and order, and yes, on the width specifiers if possible.

Quoted 8 lines

spacing with a special character in the format string, that is:

	"%S.%Qr.%Qs  %Al:%Pl %Ar:%Pr  %p\n"

would mean "align everything to the right, distribute remaining whitespace between %S, %Qr and %Qs". But it looks rather complicated at a glance.

My concern here is that once this goes in for 1 command, the others in iproute2 need to follow suit - meaning same syntax style for all commands. Given that I'd prefer we get a reasonable consensus on syntax that will work across commands -- ss, ip, tc. If it is as simple as column names with a fixed order, that is fine but just give proper consideration given the impact.

The 'ip' syntax for example gets ugly quick with the various link types and their options. We don't need to allow every detail of each link type to be customized, but there are common attributes for links (e.g., mtu, ifindex, link flags, lladdr), addresses, and link types such as bridges and bonds where we can improve the amount of data thrown at a user -- a better, more customizable version of what the brief option targeted.

#9 lore raw
Quoted 9 lines · David Ahern
Quoted 8 lines

spacing with a special character in the format string, that is:

	"%S.%Qr.%Qs  %Al:%Pl %Ar:%Pr  %p\n"

would mean "align everything to the right, distribute remaining whitespace between %S, %Qr and %Qs". But it looks rather complicated at a glance.

Quoted 6 lines

My concern here is that once this goes in for 1 command, the others in iproute2 need to follow suit - meaning same syntax style for all commands. Given that I'd prefer we get a reasonable consensus on syntax that will work across commands -- ss, ip, tc. If it is as simple as column names with a fixed order, that is fine but just give proper consideration given the impact.

FWIW I just started piping iproute2 commands to jq. Example:

tc -s -j qdisc show dev em1 | \
	jq -r '.[] |  [.kind,.parent,.handle,.offloaded,.bytes,.packets,.drops,.overlimits,.requeues,.backlog,.qlen,.marked] | @tsv'

JSONification would probably be quite an undertaking for ss :(

#10 lore raw
Quoted 17 lines · Jakub Kicinski
Quoted 9 lines · David Ahern
Quoted 8 lines

spacing with a special character in the format string, that is:

	"%S.%Qr.%Qs  %Al:%Pl %Ar:%Pr  %p\n"

would mean "align everything to the right, distribute remaining whitespace between %S, %Qr and %Qs". But it looks rather complicated at a glance.

Quoted 6 lines

My concern here is that once this goes in for 1 command, the others in iproute2 need to follow suit - meaning same syntax style for all commands. Given that I'd prefer we get a reasonable consensus on syntax that will work across commands -- ss, ip, tc. If it is as simple as column names with a fixed order, that is fine but just give proper consideration given the impact.

Quoted 7 lines

FWIW I just started piping iproute2 commands to jq. Example:

tc -s -j qdisc show dev em1 | \
	jq -r '.[] |  [.kind,.parent,.handle,.offloaded,.bytes,.packets,.drops,.overlimits,.requeues,.backlog,.qlen,.marked] | @tsv'

JSONification would probably be quite an undertaking for ss :(

Right, that is used in some of the scripts under tools/testing/selftests. I would put that in the 'heavyweight solution' category.

A number of key commands offer the capability to control the output via command line argument (e.g., ps, perf script). Given the amount of data iproute2 commands throw at a user by default, it would be a good usability feature to allow a user to customize the output without having to pipe it into other commands.

#11 lore raw
Quoted 30 lines · On Thu, 1 Nov 2018 15:18:03 -0600 David Ahern <[email protected]> wrote:
Quoted 17 lines · Jakub Kicinski
Quoted 9 lines · David Ahern
Quoted 8 lines

spacing with a special character in the format string, that is:

	"%S.%Qr.%Qs  %Al:%Pl %Ar:%Pr  %p\n"

would mean "align everything to the right, distribute remaining whitespace between %S, %Qr and %Qs". But it looks rather complicated at a glance.

Quoted 6 lines

My concern here is that once this goes in for 1 command, the others in iproute2 need to follow suit - meaning same syntax style for all commands. Given that I'd prefer we get a reasonable consensus on syntax that will work across commands -- ss, ip, tc. If it is as simple as column names with a fixed order, that is fine but just give proper consideration given the impact.

Quoted 7 lines

FWIW I just started piping iproute2 commands to jq. Example:

tc -s -j qdisc show dev em1 | \
	jq -r '.[] |  [.kind,.parent,.handle,.offloaded,.bytes,.packets,.drops,.overlimits,.requeues,.backlog,.qlen,.marked] | @tsv'

JSONification would probably be quite an undertaking for ss :(

Right, that is used in some of the scripts under tools/testing/selftests. I would put that in the 'heavyweight solution' category.

Quoted 5 lines

A number of key commands offer the capability to control the output via command line argument (e.g., ps, perf script). Given the amount of data iproute2 commands throw at a user by default, it would be a good usability feature to allow a user to customize the output without having to pipe it into other commands.

I would rather see ss grow json support than having to make the output formatting of every iproute2 command grow a new format management.

The jq tool looks cool, and I can see how someone could easily have a bunch of mini-scripts to do what they want.

#13 lore raw
In reply to David Ahern
Quoted 10 lines · On Wed, 31 Oct 2018 20:48:05 -0600 David Ahern <[email protected]> wrote:
Quoted 6 lines · Stefano Brivio

- the current column abstraction is rather lightweight, things are already buffered in the defined column order so we don't have to jump back and forth in the buffer while rendering. Doing that needs some extra care to avoid a performance hit, but it's probably doable, I can put that on my to-do list

The ss command is always a pain; it's much better in newer releases but I am always having to adjust terminal width.

Ouch. Do you have some examples?

Signature · 1 line
Stefano
#12 lore raw
In reply to Jakub Kicinski
Quoted 1 line · On Thu, 1 Nov 2018 14:06:23 -0700 Jakub Kicinski <[email protected]> wrote:

JSONification would probably be quite an undertaking for ss :(

Probably not too much, and we would skip buffering for JSON as we don't need to print columns, so we don't have to care about buffering and rendering performance too much.

All it takes is to extend a bit the out() function and pass the right arguments to it -- it looks way easier than implementing format strings, even though I'd like the latter more.

Signature · 1 line
Stefano