All of lore.kernel.org
 help / color / mirror / Atom feed
* full ss json support and general output simplification
@ 2015-08-09 23:13 Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

TLDR:

- add full JSON support for ss
- Patchset provides a general and easy to use abstraction to extend ss later
- Patchset size is large to minimize daily use ("user" should not deal with
  	formation (json, human readble) later on)
- Patches 8/10 and 9/10 illustrate how to extend ss for new data to support human readble and json
	output. 
- Example_Usages: 1. ss -jt to print out all tcp related information formatted in json
		  2. ss --json -a to print out all info (also summary) 


STATS:

Matthias Tafelmeier (10):
  ss: rooted out ss type declarations for output formatters
  ss: created formatters for json and hr
  ss: removed obsolet fmt functions
  ss: prepare timer for output handler usage
  ss: framed skeleton for json output in ss
  ss: replaced old output mechanisms with fmt handlers interfaces
  ss: renaming and export of current_filter
  ss: symmetrical subhandler output extension example
  ss: symmetrical formatter extension example
  ss: fixed free on local array for valid json output

 misc/Makefile      |    2 +-
 misc/ss.c          | 1010 +++++++++++++++++++---------------------------------
 misc/ss_hr_fmt.c   |  321 +++++++++++++++++
 misc/ss_hr_fmt.h   |    9 +
 misc/ss_json_fmt.c |  466 ++++++++++++++++++++++++
 misc/ss_json_fmt.h |   24 ++
 misc/ss_out_fmt.c  |  137 +++++++
 misc/ss_out_fmt.h  |   92 +++++
 misc/ss_types.h    |  186 ++++++++++
 9 files changed, 1595 insertions(+), 652 deletions(-)
 create mode 100644 misc/ss_hr_fmt.c
 create mode 100644 misc/ss_hr_fmt.h
 create mode 100644 misc/ss_json_fmt.c
 create mode 100644 misc/ss_json_fmt.h
 create mode 100644 misc/ss_out_fmt.c
 create mode 100644 misc/ss_out_fmt.h
 create mode 100644 misc/ss_types.h

-- 

Abstract: 

This patch set originates from the necessity to upgrade ss with the possibility
to output in json format. Not to clutter up ss too much, the author of the
patch decided to come up with a simple distributor to handler approach. That
is, the distributor poses the mechanical interface which passes the output
requests coming from ss to the appropriate handler. This simplifies the
interaction with ss and provides a maximum of future extensiblity. Not to
forget, ss loses weight thereby since output implemented in ss itself does
migrate to the appropriate handler. Additionally, because types are shared
amongst handlers, the distributor and ss, the author conceived, that a separate
containter module for types has to be formed. In future, all type declarations
and extensins go there. 

In sum, the patchset has this voluminous extent since there is no viable way
for putting out syntactically correct human readble and json in a simpler manner.
The requirement for convenient extensibility of output and data is
another justification for the patchset size.

Concept sketch:

                                               formatter1 
                                              ************                
                                              *          *                
                                              *          *                
           ss                           ~~~~~~~>zzzzzzz  *                
     ******************                 ~     *          *                
     *                *                 ~   ###>fffffff  *                
     *                *                 ~   # *          *                
     *                *      distributor~   # ************                
     *   --------     *       ********* ~   #                             
     *   -    --------------  *       * ~   #                             
     *   --------     *    -  *       * ~   #                             
     *                *    ---->++++ ~~~~   #                             
     *                *       *       * ~   #  formatter2 
     *                *    ---->==== ######## ************                
     *   --------     *    -  *       * ~   # *          *                
     *   -    --------------  *       * ~   # *          *                
     *   --------     *       ********* ~   # *          *                
     *                *                 ~~~~#~~>zzzzzzz  *                
     *                *                     # *          *                
     *                *                     ###>fffffff	 *                
     ******************                       *          *                
                                              ************                
						                       
At the moment, the distributor is the ss_out_fmt module while two handlers are
up: namely the ss_json_fmt and the ss_hr_fmt (human readable). You can use
those modules as the main reference for own extensions.

Future Extension:
In the following, I will expand on the expandability of the formatter model.
The explanations advances from the minimal to the most sweeping extension in
mind.

Sub Format Handler Output 
Sketch

		  FormatterX
                  ***********************************                     
                  *                                 *                     
                  *   handlerX 			    *                     
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *                     
                  *   °                        °    *                     
                  *   °    xxxxxxxxxxxxxxc<..  °    *                     
                  *   °                     .  °    *                     
                  *   °    xxxxxxxxxxxxxxc<.. potential context                  
                  *   °        new:         .  °    *      
                  *   °    +++++++++++++++... < * * * * * * * * * * *       
                  *   °                        °    *               *      
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *               *      
                  *               .                 *               *      
                  *               .                 *               *      
                  *               .                 *               *      
                  *   handlerY		  	    *               *      
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *               *      
                  *   °                        °    *               *      
                  *   °    xxxxxxxxxxxxxxx     °    *               *      
                  *   °                        °    *               *      
                  *   °    xxxxxxxxxxxxxxx     °    *               *      
                  *   °                        °    *               *   expand symmetrically   
                  *   °                        °    *               *      
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *               *      
                  *                                 *               *      
                  *                                 *               *      
                  *                                 *               *      
                  ***********************************          	    *
								    *
		 		.				    *
				.				    *
				.				    *
				 				    *
		  FormatterY					    *
                  ***********************************               *     
                  *                                 *               *     
                  *   handlerX			    *               *      
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *               *      
                  *   °                        °    *               *      
                  *   °    zzzzzzzzzzzzzzc<..  °    *               *      
                  *   °                     .  °    *               *      
                  *   °    zzzzzzzzzzzzzzc<.. potential context     *              
                  *   °        new:         .  °    *               *     
                  *   °    +++++++++++++++... < * * * * * * * * * * *     
                  *   °                        °    *                     
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *                     
                  *               .                 *                     
                  *               .                 *                     
                  *               .                 *                     
                  *   handlerY		  	    *                     
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *                     
                  *   °                        °    *                     
                  *   °    zzzzzzzzzzzzzzz     °    *                     
                  *   °                        °    *                     
                  *   °    zzzzzzzzzzzzzzz     °    *                     
                  *   °                        °    *                     
                  *   °                        °    *                     
                  *   °°°°°°°°°°°°°°°°°°°°°°°°°°    *                     
                  *                                 *                     
                  *                                 *                     
                  ***********************************     

Explanation:
If you plan to expand a sub out handler function of a formatter, it
essentially boils down to adding a new printf with an according format and
probably a necessary predicate (condition). Nontheless, care must be taken not
to lose possible context interdependecies out of sight. An examble for the
latter would be the interdependecy of json coma setting terms – in compound
types, you do need a coma between consecutive elements.

More important is the issue about symmetric extensions. Except for the
tcp_out_fmt function implementation – where a macro (CHECK_FMT_ADAPT) is in
place to check for adaptions in the basic tcpstat data structure statically –
no general programmatic approach is in place yet which would prevent asymmetric
extensions. Up to someone devices a holistic solution, this patch relies on the
extenders to deal with asymmetries. Is the aim to have a new output feature
available in all semantically related handlers of n different formatters, then
the expander has to adapt n handlers as shown in the sketch above.

Example:
Let's take a look at the ss_json_fmt formatter module for a concrete example.
Were you to to extend the formatting handler tcp_stats_json_fmt, then it could
look as follows:

*** PSEUDO_CODE ***

static void tcp_stats_json_fmt(struct tcpstat *s)
{
	char b1[64];

	char indent1[] = "\t";
	char indent2[] = "\t\t";

	[...]	

		if (s->has_ts_opt) {
			printf(",\n%s\"ts\": \"true\"", indent1);
		}
	if (s->has_sack_opt) {
		printf(",\n%s\"sack\": \"true\"", indent1);
	}

--->>>	if (s->new_info) {
		printf(",\n%s\"new_info\": \"XYZ\"", indent1);
	}

	[...]	
}

and for SYMMETRY reasons extend on hr side as well:

static void tcp_stats_hr_fmt(struct tcpstat *s)
{
	[...]	

		if (s->has_ts_opt)
			printf(" ts");
	if (s->has_sack_opt)
		printf(" sack");
--->>>	if (s->new_info)
		printf(" *content of new info*");

	[...]	
}

Extend with further Format Handler in Formatter
Sketch:
-provides symmetrical extension intendet


                                                       formatter1
                                                      /--------------------------\
                                                      |                          |
                                                      |    spec_handlerX         |
                                                      |     ################ <** |
                                                      |     ################   * |
             distributor                              |            .           * |
           O-------------------------O                |            .           * |
           |    centr_hub            |                |    new_spec_handler    * |
           | ***>01111110--------------------------+  |     ++++++++++++++++<~ * |
           | *   02222220----------------------+   |  |     ++++++++++++++++ ~ * |
           | *                       |         |   |  |                      ~ * |
           | *                       |         |   |  |      handler_hub1    ~ * |
           | *  _______________      |         |   +--------->0#########0****~** |
           | * |gen_handlerX   |     |         |      |	      0+++++++++0~~~~~   |
           | **********        |     |         |      |                          |
           | * |_______________|     |         |      |                          |
           | *         .             |         |      \--------------------------/
           | *         .             |         |                  .
           | *         .             |         |                  .
           | * +++++++++++++++++     |         |       formatterN .
           | ***new_gen_handler+     |         |      /--------------------------\
           |   +               +     |         |      |                          |
           |   +++++++++++++++++     |         |      |    spec_handlerX         |
           |                         |         |      |     ################ <** |
           O-------------------------O         |      |     ################   * |
                                               |      |            .           * |
                                               |      |            .           * |
                                               |      |    new_spec_handler    * |
                                               |      |     ++++++++++++++++<~ * |
                                               |      |     ++++++++++++++++ ~ * |
                                               |      |                      ~ * |
                                               |      |      handler_hubN    ~ * |
                                               +------------->0#########0****~** |
                                                      |	      0+++++++++0~~~~~   |
                                                      |                          |
                                                      |                          |
                                                      \--------------------------/


Explanation:
As the sketch shows, the distributor works with the help of virtual function
pointer in order to act as a call flow switch. It switches to the approriate
formatter module and its handlers depending on the chosen output format by ss
command input. 

So, to add a new formatter handler symmetrically (up to now that is the only
sensibly conceivable case), the extender must implement a new generic handler
in the distributor and the specific handlers in the formatters. Then the hub
vtable structure type has to be broadend to contain the new function pointer
type for the generic handler. After that, he has to extend and update all
handler hubs with the new handlers location information (function pointer). The
latter ensures the generic switching mechanism used by the generic handler
keeps to be upheld.

Example:
Let's say we want the new "foo" data for every output format retrievable via
ss. Up to now, we have the ss_out_fmt module as the distributor and two
specific handlers: for one the ss_hr_fmt and secondly the ss_json_fmt module.
So we need a specific handler implementation in ss_hr_fmt and ss_json_fmt
modules and after that update the corresponding vtables (handler_hubs) in the
modules.  After that, the distributor, namely ss_out_fmt module, has to get a
generic handler that switches via its vtable hub to either the json formatter
or the human readable formatter, depending on what fmt_type has been chosen by ss.
Before the vtables in the specific modules can be updated, struct fmt_op_hub
which is found in ss_out_fmt's interface header has get extendend with the new
function pointer type.

As soon the new generic handler has been exported via the ss_out_fmt.h module
interface, ss can use the new fmt handler to print out info. It can simply call
the generic function and does not have to deal with formatting specific issues.

In the following pseudo code, the additions are marked with an arrow. 

*** PSEUDO_CODE ***
### ss_out_fmt.h ###
struct fmt_op_hub {
	void (*tcp_stats_fmt)(struct tcpstat *s);
	void (*tcp_timer_fmt)(struct tcpstat *s);
	[...]	
	void (*packet_details_fmt)(struct packet_diag_info * pinfo,
			struct packet_diag_ring * ring_rx,
			struct packet_diag_ring * ring_tx,
			uint32_t fanout,
			bool has_fanout);
	void (*packet_show_ring_fmt)(struct packet_diag_ring *ring);
->>> 	void (*new_gen_foo_handler_fmt)(int xy);
};

### ss_out_fmt.c ###
	[...]	
void sock_users_fmt(char *out)
{
	fmt_op_hub[fmt_type]->sock_users_fmt(out);
}

->>> void new_gen_foo_handler_fmt(int xy)
{
	fmt_op_hub[fmt_type]->spec_foo_handler_fmt(out);
}
	[...]	

### ss_hr_fmt.c ###
	[...]	
static void sock_users_hr_fmt(char *out)
{
	printf(" users:(%s)", out);
}

->>> void spec_foo_handler_hr_fmt(int xy)
{
	printf(" foo: %d", xy);
}
	[...]	
const struct fmt_op_hub hr_output_op = {
	.tcp_stats_fmt = tcp_stats_hr_fmt,
	.tcp_timer_fmt = tcp_timer_hr_fmt,
	[...]	
	.packet_details_fmt = packet_details_hr_fmt,
	.packet_show_ring_fmt = packet_show_ring_hr_fmt,
->>>	.new_gen_foo_handler_fmt = spec_foo_handler_hr_fmt
};

### ss_json_fmt.c ###
	[...]	
static void sock_users_json_fmt(char *out)
{
	make_userout_valid(out);

	printf(",\n\t\"users\": \"%s\"", out);
}

->>> void spec_foo_handler_json_fmt(int xy)
{
	printf(",\n\t\"foo\": \"%d\"", xy);
}
	[...]	
const struct fmt_op_hub json_output_op = {
	.tcp_stats_fmt = tcp_stats_json_fmt,
	.tcp_timer_fmt = tcp_timer_json_fmt,
	[...]	
	.packet_details_fmt = packet_details_json_fmt,
	.packet_show_ring_fmt = packet_show_ring_json_fmt,  
->>>	.new_gen_foo_handler_fmt = spec_foo_handler_json_fmt 
};

Extend for another Formatter 
Sketch:
The Sketch for handler extension should be sufficient for conveying the concept.
Just think of another formatter after formatterN and a new entry in the central
vtable of the distributor to reach this new formatter.

Explanation:
Nothing breathtaking has to be done when someone needs an new formatter module
for let's be image – out of pure hypothetical endeavors – xml ss output. First,
implement the new formatter with all the offered interfaces in the
distributor. Register all handlers in the local specific vtable hub.
Then, register the local vtable hub in the generic vtable hub of the
distributor to reach your new handler when chosen. Provide the client
code - here ss - with a new fmt_type option acceptance. Before the
option can do anything, you have to declare the new fmt_type. That's
it. No further adaptions in ss would be necessary.

Example:
Extensions are highlighted with an arrow, as previously done.

### ss_out_fmt.h ###

enum out_fmt_type { FMT_HR, FMT_JSON,->>> FMT_NEW};

### ss_out_fmt.c ###
	[...]
const struct fmt_op_hub *fmt_op_hub[] = {
	/*human readble */
	&hr_output_op,
	/*json */
	&json_output_op,
	/*new */
	&new_output_op 
};
	[...]

### ss_new_fmt.c ###
	[...]
->>> static void sock_users_new_fmt(char *out)
{
	make_userout_valid(out);

	printf("NEW OUTFMT: %s", out);
}
	[...]
const struct fmt_op_hub new_output_op = {
	.tcp_stats_fmt = ->>> tcp_stats_new_fmt,
	.tcp_timer_fmt = ->>> tcp_timer_new_fmt,
	[...]	
	.sock_users_fmt = ->>> sock_users_new_fmt,
	[...]	
	.packet_details_fmt = ->>> packet_details_new_fmt,
	.packet_show_ring_fmt =->>> packet_show_ring_new_fmt,  
};
### ss.c ###
	[...]
int json_output = 0;
->>> int new_output = 0;
	[...]
case 'j':
	fmt_type = FMT_JSON;
	json_output = 1;
	break;
->>>case 'N':
->>>	fmt_type = FMT_NEW;
->>>	new_output = 1;
->>>	break;
case 'h':
	[...]

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

* [PATCH 01/10] ss: rooted out ss type declarations for output formatters
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 02/10] ss: created formatters for json and hr Matthias Tafelmeier
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

The prospected output formatters and ss do share type declarations like
slabstat or tcpstat so that the decision has been made to centralize
those declarations in ss_types.h.  Potential future declarations shall
be placed there. The latter should help amend the extent of ss.c as
well.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>

---
 misc/ss.c       | 186 +-------------------------------------------------------
 misc/ss_types.h | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 187 insertions(+), 185 deletions(-)
 create mode 100644 misc/ss_types.h

diff --git a/misc/ss.c b/misc/ss.c
index f4c828c..3d31b81 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -27,6 +27,7 @@
 #include <getopt.h>
 #include <stdbool.h>
 
+#include "ss_types.h"
 #include "utils.h"
 #include "rt_names.h"
 #include "ll_map.h"
@@ -113,55 +114,17 @@ static const char *UDP_PROTO = "udp";
 static const char *RAW_PROTO = "raw";
 static const char *dg_proto = NULL;
 
-enum
-{
-	TCP_DB,
-	DCCP_DB,
-	UDP_DB,
-	RAW_DB,
-	UNIX_DG_DB,
-	UNIX_ST_DB,
-	UNIX_SQ_DB,
-	PACKET_DG_DB,
-	PACKET_R_DB,
-	NETLINK_DB,
-	MAX_DB
-};
 
 #define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
 #define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
 #define ALL_DB ((1<<MAX_DB)-1)
 #define INET_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<RAW_DB))
 
-enum {
-	SS_UNKNOWN,
-	SS_ESTABLISHED,
-	SS_SYN_SENT,
-	SS_SYN_RECV,
-	SS_FIN_WAIT1,
-	SS_FIN_WAIT2,
-	SS_TIME_WAIT,
-	SS_CLOSE,
-	SS_CLOSE_WAIT,
-	SS_LAST_ACK,
-	SS_LISTEN,
-	SS_CLOSING,
-	SS_MAX
-};
-
 #define SS_ALL ((1 << SS_MAX) - 1)
 #define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
 
 #include "ssfilter.h"
 
-struct filter
-{
-	int dbs;
-	int states;
-	int families;
-	struct ssfilter *f;
-};
-
 static const struct filter default_dbs[MAX_DB] = {
 	[TCP_DB] = {
 		.states   = SS_CONN,
@@ -376,16 +339,6 @@ static FILE *ephemeral_ports_open(void)
 	return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
 }
 
-struct user_ent {
-	struct user_ent	*next;
-	unsigned int	ino;
-	int		pid;
-	int		fd;
-	char		*process;
-	char		*process_ctx;
-	char		*socket_ctx;
-};
-
 #define USER_ENT_HASH_SIZE	256
 struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
 
@@ -538,12 +491,6 @@ static void user_ent_hash_build(void)
 	closedir(dir);
 }
 
-enum entry_types {
-	USERS,
-	PROC_CTX,
-	PROC_SOCK_CTX
-};
-
 #define ENTRY_BUF_SIZE 512
 static int find_entry(unsigned ino, char **buf, int type)
 {
@@ -616,17 +563,6 @@ next:
 	return cnt;
 }
 
-/* Get stats from slab */
-
-struct slabstat
-{
-	int socks;
-	int tcp_ports;
-	int tcp_tws;
-	int tcp_syns;
-	int skbs;
-};
-
 static struct slabstat slabstat;
 
 static const char *slabstat_ids[] =
@@ -711,75 +647,6 @@ static const char *sstate_namel[] = {
 	[SS_CLOSING] = "closing",
 };
 
-struct sockstat
-{
-	struct sockstat	   *next;
-	unsigned int	    type;
-	uint16_t	    prot;
-	inet_prefix	    local;
-	inet_prefix	    remote;
-	int		    lport;
-	int		    rport;
-	int		    state;
-	int		    rq, wq;
-	unsigned	    ino;
-	unsigned	    uid;
-	int		    refcnt;
-	unsigned int	    iface;
-	unsigned long long  sk;
-	char *name;
-	char *peer_name;
-};
-
-struct dctcpstat
-{
-	unsigned int	ce_state;
-	unsigned int	alpha;
-	unsigned int	ab_ecn;
-	unsigned int	ab_tot;
-	bool		enabled;
-};
-
-struct tcpstat
-{
-	struct sockstat	    ss;
-	int		    timer;
-	int		    timeout;
-	int		    probes;
-	char		    cong_alg[16];
-	double		    rto, ato, rtt, rttvar;
-	int		    qack, cwnd, ssthresh, backoff;
-	double		    send_bps;
-	int		    snd_wscale;
-	int		    rcv_wscale;
-	int		    mss;
-	unsigned int	    lastsnd;
-	unsigned int	    lastrcv;
-	unsigned int	    lastack;
-	double		    pacing_rate;
-	double		    pacing_rate_max;
-	unsigned long long  bytes_acked;
-	unsigned long long  bytes_received;
-	unsigned int	    segs_out;
-	unsigned int	    segs_in;
-	unsigned int	    unacked;
-	unsigned int	    retrans;
-	unsigned int	    retrans_total;
-	unsigned int	    lost;
-	unsigned int	    sacked;
-	unsigned int	    fackets;
-	unsigned int	    reordering;
-	double		    rcv_rtt;
-	int		    rcv_space;
-	bool		    has_ts_opt;
-	bool		    has_sack_opt;
-	bool		    has_ecn_opt;
-	bool		    has_ecnseen_opt;
-	bool		    has_fastopen_opt;
-	bool		    has_wscale_opt;
-	struct dctcpstat    *dctcp;
-};
-
 static void sock_state_print(struct sockstat *s, const char *sock_name)
 {
 	if (netid_width)
@@ -853,13 +720,6 @@ static const char *print_ms_timer(int timeout)
 	return buf;
 }
 
-struct scache {
-	struct scache *next;
-	int port;
-	char *name;
-	const char *proto;
-};
-
 struct scache *rlist;
 
 static void init_service_resolver(void)
@@ -1024,13 +884,6 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex
 			ifname);
 }
 
-struct aafilter
-{
-	inet_prefix	addr;
-	int		port;
-	struct aafilter *next;
-};
-
 static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
 			    int plen)
 {
@@ -2186,11 +2039,6 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
 	return 0;
 }
 
-struct inet_diag_arg {
-	struct filter *f;
-	int protocol;
-};
-
 static int show_one_inet_sock(const struct sockaddr_nl *addr,
 		struct nlmsghdr *h, void *arg)
 {
@@ -3218,10 +3066,6 @@ 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)
 {
@@ -3276,11 +3120,6 @@ Exit:
 	return ret;
 }
 
-struct snmpstat
-{
-	int tcp_estab;
-};
-
 static int get_snmp_int(char *proto, char *key, int *result)
 {
 	char buf[1024];
@@ -3325,28 +3164,6 @@ static int get_snmp_int(char *proto, char *key, int *result)
 	return -1;
 }
 
-
-/* Get stats from sockstat */
-
-struct ssummary
-{
-	int socks;
-	int tcp_mem;
-	int tcp_total;
-	int tcp_orphans;
-	int tcp_tws;
-	int tcp4_hashed;
-	int udp4;
-	int raw4;
-	int frag4;
-	int frag4_mem;
-	int tcp6_hashed;
-	int udp6;
-	int raw6;
-	int frag6;
-	int frag6_mem;
-};
-
 static void get_sockstat_line(char *line, struct ssummary *s)
 {
 	char id[256], rem[256];
@@ -3811,7 +3628,6 @@ int main(int argc, char *argv[])
 	    (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
 		init_service_resolver();
 
-
 	if (current_filter.dbs == 0) {
 		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
 		exit(0);
diff --git a/misc/ss_types.h b/misc/ss_types.h
new file mode 100644
index 0000000..86acb8a
--- /dev/null
+++ b/misc/ss_types.h
@@ -0,0 +1,186 @@
+#ifndef SS_STRUCTS_H
+#define SS_STRUCTS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "utils.h"
+
+enum {
+       TCP_DB,
+       DCCP_DB,
+       UDP_DB,
+       RAW_DB,
+       UNIX_DG_DB,
+       UNIX_ST_DB,
+       UNIX_SQ_DB,
+       PACKET_DG_DB,
+       PACKET_R_DB,
+       NETLINK_DB,
+       MAX_DB
+};
+
+enum {
+	SS_UNKNOWN,
+	SS_ESTABLISHED,
+	SS_SYN_SENT,
+	SS_SYN_RECV,
+	SS_FIN_WAIT1,
+	SS_FIN_WAIT2,
+	SS_TIME_WAIT,
+	SS_CLOSE,
+	SS_CLOSE_WAIT,
+	SS_LAST_ACK,
+	SS_LISTEN,
+	SS_CLOSING,
+	SS_MAX
+};
+
+struct filter {
+	int dbs;
+	int states;
+	int families;
+	struct ssfilter *f;
+};
+
+struct user_ent {
+	struct user_ent *next;
+	unsigned int ino;
+	int pid;
+	int fd;
+	char *process;
+	char *process_ctx;
+	char *socket_ctx;
+};
+
+/* Get stats from slab */
+
+struct slabstat {
+	int socks;
+	int tcp_ports;
+	int tcp_tws;
+	int tcp_syns;
+	int skbs;
+};
+
+struct sockstat {
+	struct sockstat    *next;
+	unsigned int        type;
+	uint16_t            prot;
+	inet_prefix         local;
+	inet_prefix         remote;
+	int                 lport;
+	int                 rport;
+	int                 state;
+	int                 rq, wq;
+	unsigned            ino;
+	unsigned            uid;
+	int                 refcnt;
+	unsigned int        iface;
+	unsigned long long  sk;
+	char *name;
+	char *peer_name;
+};
+
+struct dctcpstat {
+	unsigned int ce_state;
+	unsigned int alpha;
+	unsigned int ab_ecn;
+	unsigned int ab_tot;
+	bool enabled;
+};
+
+#pragma pack(push, 1)
+
+struct tcpstat {
+	struct sockstat     ss;
+	int                 timer;
+	int                 timeout;
+	int                 probes;
+	char                cong_alg[16];
+	double              rto, ato, rtt, rttvar;
+	int                 qack, cwnd, ssthresh, backoff;
+	double              send_bps;
+	int                 snd_wscale;
+	int                 rcv_wscale;
+	int                 mss;
+	unsigned int        lastsnd;
+	unsigned int        lastrcv;
+	unsigned int        lastack;
+	double              pacing_rate;
+	double              pacing_rate_max;
+	unsigned long long  bytes_acked;
+	unsigned long long  bytes_received;
+	unsigned int        segs_out;
+	unsigned int        segs_in;
+	unsigned int        unacked;
+	unsigned int        retrans;
+	unsigned int        retrans_total;
+	unsigned int        lost;
+	unsigned int        sacked;
+	unsigned int        fackets;
+	unsigned int        reordering;
+	bool                has_ts_opt;
+	bool                has_sack_opt;
+	bool                has_ecn_opt;
+	bool                has_ecnseen_opt;
+	bool                has_fastopen_opt;
+	bool                has_wscale_opt;
+	struct dctcpstat    *dctcp;
+	double              rcv_rtt;
+	int                 rcv_space;
+};
+
+#pragma pack(pop)
+
+struct scache {
+	struct scache *next;
+	int port;
+	char *name;
+	const char *proto;
+};
+
+struct aafilter {
+	inet_prefix addr;
+	int port;
+	struct aafilter *next;
+};
+
+struct snmpstat {
+	int tcp_estab;
+};
+
+struct sock_diag_msg {
+	__u8 sdiag_family;
+};
+
+struct inet_diag_arg {
+	struct filter *f;
+	int protocol;
+};
+
+/* Get stats from sockstat */
+
+struct ssummary {
+	int socks;
+	int tcp_mem;
+	int tcp_total;
+	int tcp_orphans;
+	int tcp_tws;
+	int tcp4_hashed;
+	int udp4;
+	int raw4;
+	int frag4;
+	int frag4_mem;
+	int tcp6_hashed;
+	int udp6;
+	int raw6;
+	int frag6;
+	int frag6_mem;
+};
+
+enum entry_types {
+	USERS,
+	PROC_CTX,
+	PROC_SOCK_CTX
+};
+#endif				/* SS_STRUCTS_H */
-- 
1.9.1

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

* [PATCH 02/10] ss: created formatters for json and hr
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 03/10] ss: removed obsolet fmt functions Matthias Tafelmeier
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

This patch creates a central formatter module that acts as a kind of
switch. From there, more specific handler modules for the certain output
formats are called. Up to now, humand readable and json do exist.

That prepares ss for potential output format extensions in the future.
With the help of such an apparatus, extensions should get done
conveniently as well.

For a completely new output format, a new handler module must be created
and should be constructed like its relatives (for ex.: ss_json_fmt.c).
Moreover, its functions need to get registered with the central output
distributor. The latter can be done in that the according fmt_op_hub of
the new handler module is registered in the fmt_op_hub array.

Solely extending tcp_stats output shall boil down to extending the
according handler function with the new predicate and its value. The
context of the output subparts are important. With JSON, for instance,
you have to ensure, that the comas are set at the right places.

Further, an interim solution for all tcp_stats extensions is to check
that all those muddle through to all fmt handlers by STATICAL_ASSERTING
that.  Interim is the solution, since a central structure would be much
more worthwile for maintainability and this method does not ensure
correct output fmt extension in a foolproof manner.

Examples for tcp_stats out extension:

ss_json_fmt.c:

To add a new foo_param in tcp_stats for output (Pseudocode):
	[...]
	if (s->has_ts_opt) {
		printf(",\n%s\"ts\": \"true\"", indent1);
	}
	if (s->has_sack_opt) {
		printf(",\n%s\"sack\": \"true\"", indent1);
	}
	if (s->has_ecn_opt) {
		printf(",\n%s\"ecn\": \"true\"", indent1);
	}
	[...]

	-> macro to ensure statically no new tcp_stats info will be forgotten in
	-> any of the fmt handlers
	CHECK_FMT_ADAPT(s->new_foo_pred, s, error_msg_adapation_issue);

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/Makefile      |   2 +-
 misc/ss_hr_fmt.c   | 258 ++++++++++++++++++++++++++++++++++
 misc/ss_hr_fmt.h   |   9 ++
 misc/ss_json_fmt.c | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_json_fmt.h |  24 ++++
 misc/ss_out_fmt.c  | 127 +++++++++++++++++
 misc/ss_out_fmt.h  |  82 +++++++++++
 7 files changed, 900 insertions(+), 1 deletion(-)
 create mode 100644 misc/ss_hr_fmt.c
 create mode 100644 misc/ss_hr_fmt.h
 create mode 100644 misc/ss_json_fmt.c
 create mode 100644 misc/ss_json_fmt.h
 create mode 100644 misc/ss_out_fmt.c
 create mode 100644 misc/ss_out_fmt.h

diff --git a/misc/Makefile b/misc/Makefile
index b7ecba9..fb67ead 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -1,4 +1,4 @@
-SSOBJ=ss.o ssfilter.o
+SSOBJ=ss.o ssfilter.o ss_hr_fmt.o ss_json_fmt.o ss_out_fmt.o
 LNSTATOBJ=lnstat.o lnstat_util.o
 
 TARGETS=ss nstat ifstat rtacct arpd lnstat
diff --git a/misc/ss_hr_fmt.c b/misc/ss_hr_fmt.c
new file mode 100644
index 0000000..6955ea5
--- /dev/null
+++ b/misc/ss_hr_fmt.c
@@ -0,0 +1,258 @@
+#include <linux/sock_diag.h>
+#include <linux/rtnetlink.h>
+#include "ss_out_fmt.h"
+#include "ss_types.h"
+#include "ss_hr_fmt.h"
+
+static void tcp_stats_hr_fmt(struct tcpstat *s)
+{
+	char b1[64];
+
+	if (s->has_ts_opt)
+		printf(" ts");
+	if (s->has_sack_opt)
+		printf(" sack");
+	if (s->has_ecn_opt)
+		printf(" ecn");
+	if (s->has_ecnseen_opt)
+		printf(" ecnseen");
+	if (s->has_fastopen_opt)
+		printf(" fastopen");
+	if (s->cong_alg)
+		printf(" %s", s->cong_alg);
+	if (s->has_wscale_opt)
+		printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
+	if (s->rto)
+		printf(" rto:%g", s->rto);
+	if (s->backoff)
+		printf(" backoff:%u", s->backoff);
+	if (s->rtt)
+		printf(" rtt:%g/%g", s->rtt, s->rttvar);
+	if (s->ato)
+		printf(" ato:%g", s->ato);
+
+	if (s->qack)
+		printf(" qack:%d", s->qack);
+	if (s->qack & 1)
+		printf(" bidir");
+
+	if (s->mss)
+		printf(" mss:%d", s->mss);
+	if (s->cwnd)
+		printf(" cwnd:%d", s->cwnd);
+	if (s->ssthresh)
+		printf(" ssthresh:%d", s->ssthresh);
+
+	if (s->dctcp && s->dctcp->enabled) {
+		struct dctcpstat *dctcp = s->dctcp;
+
+		printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
+		dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
+		dctcp->ab_tot);
+	} else if (s->dctcp) {
+		printf(" dctcp:fallback_mode");
+	}
+
+	if (s->send_bps)
+		printf(" send %sbps", sprint_bw(b1, s->send_bps));
+	if (s->lastsnd)
+		printf(" lastsnd:%u", s->lastsnd);
+	if (s->lastrcv)
+		printf(" lastrcv:%u", s->lastrcv);
+	if (s->lastack)
+		printf(" lastack:%u", s->lastack);
+
+	if (s->pacing_rate) {
+		printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
+		if (s->pacing_rate_max)
+			printf("/%sbps", sprint_bw(b1, s->pacing_rate_max));
+	}
+
+	if (s->unacked)
+		printf(" unacked:%u", s->unacked);
+	if (s->retrans || s->retrans_total)
+		printf(" retrans:%u/%u", s->retrans, s->retrans_total);
+	if (s->lost)
+		printf(" lost:%u", s->lost);
+	if (s->sacked && s->ss.state != SS_LISTEN)
+		printf(" sacked:%u", s->sacked);
+	if (s->fackets)
+		printf(" fackets:%u", s->fackets);
+	if (s->reordering != 3)
+		printf(" reordering:%d", s->reordering);
+	if (s->rcv_rtt)
+		printf(" rcv_rtt:%g", s->rcv_rtt);
+
+	CHECK_FMT_ADAPT(s->rcv_space, s,
+	hr_handler_must_be_adapted_accordingly_when_json_fmt_is_extended);
+}
+
+static void tcp_timer_hr_fmt(struct tcpstat *s)
+{
+	if (s->timer) {
+		if (s->timer > 4)
+			s->timer = 5;
+		printf(" timer:(%s,%s,%d)",
+		ss_timer_name[s->timer],
+		print_ms_timer(s->timeout), s->retrans);
+	}
+}
+
+static void sock_state_hr_fmt(struct sockstat *s, const char **sstate_name,
+		const char *sock_name, int netid_width, int state_width)
+{
+	if (netid_width)
+		printf("%-*s ", netid_width, sock_name);
+	if (state_width)
+		printf("%-*s ", state_width, sstate_name[s->state]);
+
+	printf("%-6d %-6d ", s->rq, s->wq);
+}
+
+static void sock_details_hr_fmt(struct sockstat *s, int type, unsigned groups,
+			unsigned long long cb)
+{
+	if (type == GENERIC_DETAIL && s->uid)
+		printf(" uid:%u", s->uid);
+
+	if (type == GENERIC_DETAIL) {
+		printf(" ino:%u", s->ino);
+		printf(" sk:%llx", s->sk);
+	}
+
+	if (type == NETLINK_DETAIL)
+		printf(" sk=%llx cb=%llx groups=0x%08x", s->sk, cb, groups);
+
+}
+
+static void sock_addr_hr_fmt(const char *addr, int addr_len,
+		char *delim, int port_len,
+		const char *port, const char *ifname,
+		const char *peer_kind)
+{
+	if (ifname) {
+		printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
+		port_len, port);
+	} else {
+		printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
+	}
+}
+
+static void sock_users_hr_fmt(char *out)
+{
+	printf(" users:(%s)", out);
+}
+
+static void sock_summary_hr_fmt(struct ssummary *s, struct snmpstat *sn,
+			struct slabstat *slabstat, int has_succ)
+{
+	printf("Total: %d (kernel %d)\n", s->socks, slabstat->socks);
+
+	printf("TCP:   %d (estab %d, closed %d, orphaned %d,"
+		"synrecv %d, timewait %d/%d), ports %d\n",
+	s->tcp_total + slabstat->tcp_syns + s->tcp_tws, sn->tcp_estab,
+	s->tcp_total - (s->tcp4_hashed + s->tcp6_hashed - s->tcp_tws),
+	s->tcp_orphans, slabstat->tcp_syns, s->tcp_tws, slabstat->tcp_tws,
+	slabstat->tcp_ports);
+
+	printf("\n");
+	printf("Transport Total     IP        IPv6\n");
+	printf("*	%-9d %-9s %-9s\n", slabstat->socks, "-", "-");
+	printf("RAW	%-9d %-9d %-9d\n", s->raw4 + s->raw6, s->raw4,
+	s->raw6);
+	printf("UDP	%-9d %-9d %-9d\n", s->udp4 + s->udp6, s->udp4,
+	s->udp6);
+	printf("TCP	%-9d %-9d %-9d\n", s->tcp4_hashed + s->tcp6_hashed,
+	s->tcp4_hashed, s->tcp6_hashed);
+	printf("INET	%-9d %-9d %-9d\n",
+	s->raw4 + s->udp4 + s->tcp4_hashed + s->raw6 + s->udp6 +
+	s->tcp6_hashed, s->raw4 + s->udp4 + s->tcp4_hashed,
+	s->raw6 + s->udp6 + s->tcp6_hashed);
+	printf("FRAG	%-9d %-9d %-9d\n", s->frag4 + s->frag6, s->frag4,
+	s->frag6);
+
+	printf("\n");
+}
+
+static void sock_conn_hr_fmt(unsigned char mask)
+{
+	printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+}
+
+static void mem_hr_fmt(const struct inet_diag_meminfo *minfo)
+{
+	printf(" mem:(r%u,w%u,f%u,t%u)",
+	minfo->idiag_rmem,
+	minfo->idiag_wmem, minfo->idiag_fmem, minfo->idiag_tmem);
+}
+
+static void skmem_hr_fmt(const __u32 *skmeminfo,
+		struct rtattr **tb, int attrtype)
+{
+	printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
+	skmeminfo[SK_MEMINFO_RMEM_ALLOC],
+	skmeminfo[SK_MEMINFO_RCVBUF],
+	skmeminfo[SK_MEMINFO_WMEM_ALLOC],
+	skmeminfo[SK_MEMINFO_SNDBUF],
+	skmeminfo[SK_MEMINFO_FWD_ALLOC],
+	skmeminfo[SK_MEMINFO_WMEM_QUEUED], skmeminfo[SK_MEMINFO_OPTMEM]);
+
+	if (RTA_PAYLOAD(tb[attrtype]) >=
+	(SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
+		printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
+
+	printf(")");
+}
+
+static void bpf_filter_hr_fmt(struct sock_filter *fil, int num)
+{
+	printf("\n\tbpf filter (%d): ", num);
+	while (num) {
+		printf(" 0x%02x %u %u %u,",
+		fil->code, fil->jt, fil->jf, fil->k);
+		num--;
+		fil++;
+	}
+}
+
+static void opt_hr_fmt(char *opt)
+{
+	printf(" opt:\"%s\"", opt);
+}
+
+static void proc_hr_fmt(int serv_width, char *pid_ctx)
+{
+	if (pid_ctx != NULL) {
+		printf("proc_ctx=%-*s ", serv_width, pid_ctx);
+		free(pid_ctx);
+	} else {
+		printf("proc_ctx=%-*s ", serv_width, "unavailable");
+	}
+}
+
+static void packet_show_ring_hr_fmt(struct packet_diag_ring *ring)
+{
+	printf("blk_size:%d", ring->pdr_block_size);
+	printf(",blk_nr:%d", ring->pdr_block_nr);
+	printf(",frm_size:%d", ring->pdr_frame_size);
+	printf(",frm_nr:%d", ring->pdr_frame_nr);
+	printf(",tmo:%d", ring->pdr_retire_tmo);
+	printf(",features:0x%x", ring->pdr_features);
+}
+
+const struct fmt_op_hub hr_output_op = {
+	.tcp_stats_fmt = tcp_stats_hr_fmt,
+	.tcp_timer_fmt = tcp_timer_hr_fmt,
+	.sock_state_fmt = sock_state_hr_fmt,
+	.sock_details_fmt = sock_details_hr_fmt,
+	.sock_addr_fmt = sock_addr_hr_fmt,
+	.sock_users_fmt = sock_users_hr_fmt,
+	.sock_summary_fmt = sock_summary_hr_fmt,
+	.sock_conn_fmt = sock_conn_hr_fmt,
+	.mem_fmt = mem_hr_fmt,
+	.skmem_fmt = skmem_hr_fmt,
+	.bpf_filter_fmt = bpf_filter_hr_fmt,
+	.opt_fmt = opt_hr_fmt,
+	.proc_fmt = proc_hr_fmt,
+	.packet_show_ring_fmt = packet_show_ring_hr_fmt,
+};
diff --git a/misc/ss_hr_fmt.h b/misc/ss_hr_fmt.h
new file mode 100644
index 0000000..969fb17
--- /dev/null
+++ b/misc/ss_hr_fmt.h
@@ -0,0 +1,9 @@
+#ifndef SS_HR_FMT_H
+#define SS_HR_FMT_H
+
+#include <linux/inet_diag.h>
+#include <linux/pkt_sched.h>
+#include <linux/filter.h>
+#include "ss_types.h"
+
+#endif				/* SS_HR_FMT_H */
diff --git a/misc/ss_json_fmt.c b/misc/ss_json_fmt.c
new file mode 100644
index 0000000..f1a53cd
--- /dev/null
+++ b/misc/ss_json_fmt.c
@@ -0,0 +1,399 @@
+#include <linux/sock_diag.h>
+#include <linux/rtnetlink.h>
+#include "ss_out_fmt.h"
+#include "ss_types.h"
+#include "ss_json_fmt.h"
+
+#define SHOW_TCP_INFO	(show_tcpinfo && \
+			(ss_current_filter.dbs & (1<<TCP_DB) || \
+			ss_current_filter.dbs & (1<<DCCP_DB)))
+#define SHOW_MEM	(show_mem && \
+			ss_current_filter.dbs & (1<<UDP_DB) || \
+			ss_current_filter.dbs & (1<<TCP_DB))
+
+/* generic auxiliary mechanism for json related dangling delimiter issues*/
+void res_json_fmt_branch(int pred, char bound)
+{
+	if (pred) {
+		if (bound == ' ') {
+			printf(",");
+			goto newl;
+		}
+		printf("%c,", bound);
+	} else {
+		if (bound == ' ')
+			goto newl;
+		printf("%c", bound);
+	}
+ newl:
+	printf("\n");
+}
+
+static void make_userout_valid(char *out)
+{
+	/*replace quote (") by space */
+	char *tmp;
+
+	while ((tmp = strstr(out, "\"")) != NULL)
+		*tmp = ' ';
+}
+
+static void print_serv_or_port(char *indent, char *serv_o_port)
+{
+	char buf[8];
+
+	printf(",\n");
+	if (resolve_services == 0)
+		strcpy(buf, "port");
+	else
+		strcpy(buf, "service");
+
+	printf("%s\"%s\": \"%s\"\n", indent, buf, serv_o_port);
+
+}
+
+static void tcp_stats_json_fmt(struct tcpstat *s)
+{
+	char b1[64];
+
+	char indent1[] = "\t";
+	char indent2[] = "\t\t";
+	if (s->has_ts_opt) {
+		printf(",\n%s\"ts\": \"true\"", indent1);
+	}
+	if (s->has_sack_opt) {
+		printf(",\n%s\"sack\": \"true\"", indent1);
+	}
+	if (s->has_ecn_opt) {
+		printf(",\n%s\"ecn\": \"true\"", indent1);
+	}
+	if (s->has_ecnseen_opt) {
+		printf(",\n%s\"ecnseen\": \"true\"", indent1);
+	}
+	if (s->has_fastopen_opt) {
+		printf(",\n%s\"fastopen\": \"true\"", indent1);
+	}
+	if (s->cong_alg) {
+		printf(",\n%s\"cong_alg\": \"%s\"", indent1, s->cong_alg);
+	}
+	if (s->has_wscale_opt) {
+		printf(",\n%s\"wscale\": \"%d,%d\"", indent1, s->snd_wscale,
+		s->rcv_wscale);
+	}
+	if (s->rto) {
+		printf(",\n%s\"rto\": %g", indent1, s->rto);
+	}
+	if (s->backoff) {
+		printf(",\n%s\"backoff\": %u", indent1, s->backoff);
+	}
+	if (s->rtt) {
+		printf(",\n%s\"rtt\": \"%g/%g\"", indent1, s->rtt, s->rttvar);
+	}
+	if (s->ato) {
+		printf(",\n%s\"ato\": %g", indent1, s->ato);
+	}
+	if (s->qack) {
+		printf(",\n%s\"quack\": %d", indent1, s->qack);
+	}
+	if (s->qack & 1) {
+		printf(",\n%s\"bidir\": \"true\"", indent1);
+	}
+	if (s->mss) {
+		printf(",\n%s\"mss\": %d", indent1, s->mss);
+	}
+	if (s->cwnd && s->cwnd != 2) {
+		printf("\t,\n\"cwnd\": %d", s->cwnd);
+	}
+	if (s->ssthresh) {
+		printf("\t,\n\"ssthresh\": %d", s->ssthresh);
+	}
+	if (s->dctcp && s->dctcp->enabled) {
+		struct dctcpstat *dctcp = s->dctcp;
+
+		printf(",\n\"dctcpinfo\": {\n");
+		printf(" ce_state %u,\n alpha %u,\n ab_ecn %u,\n ab_tot %u",
+		dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
+		dctcp->ab_tot);
+		printf("\n}");
+	} else if (s->dctcp) {
+		printf(",\n%s\"fallback_mode\": \"true\"", indent2);
+	}
+	if (s->send_bps) {
+		printf(",\n%s\"send\": \"%sbps\"", indent1,
+		sprint_bw(b1, s->send_bps));
+	}
+	if (s->lastsnd) {
+		printf(",\n%s\"lastsnd\": %u", indent1, s->lastsnd);
+	}
+	if (s->lastrcv) {
+		printf(",\n%s\"lastrcv\": %u", indent1, s->lastrcv);
+	}
+	if (s->lastack) {
+		printf(",\n%s\"lastack\": %u", indent1, s->lastack);
+	}
+	if (s->pacing_rate) {
+		printf(",\n%s\"pacing_rate\": \"%sbps", indent1,
+		sprint_bw(b1, s->pacing_rate));
+		if (s->pacing_rate_max)
+			printf("/%sbps\"\n", sprint_bw(b1, s->pacing_rate_max));
+		else 
+			printf("\"\n");
+	}
+	if (s->unacked) {
+		printf(",\n%s\"unacked\": %u", indent1, s->unacked);
+	}
+	if (s->retrans || s->retrans_total) {
+		printf(",\n%s\"retrans\": \"%u/%u\"", indent1, s->retrans,
+		s->retrans_total);
+	}
+	if (s->lost) {
+		printf(",\n%s\"lost\": %u", indent1, s->lost);
+	}
+	if (s->sacked && (s->ss.state != SS_LISTEN)) {
+		printf(",\n%s\"sacked\": %u", indent1, s->sacked);
+	}
+	if (s->fackets) {
+		printf(",\n%s\"fackets\": %u", indent1, s->fackets);
+	}
+	if (s->reordering != 3) {
+		printf(",\n%s\"reordering\": %d", indent1, s->reordering);
+	}
+	if (s->rcv_rtt) {
+		printf(",\n%s\"rcv_rtt\": %g", indent1, s->rcv_rtt);
+	}
+
+	/*deal with special case */
+	res_json_fmt_branch(s->ss.state == SS_LISTEN, ' ');
+
+	CHECK_FMT_ADAPT(s->rcv_space, s,
+	json_handler_must_be_adapted_accordingly_when_hr_fmt_is_extended);
+}
+
+static void tcp_timer_json_fmt(struct tcpstat *s)
+{
+	
+	if (s->timer)
+		if (s->timer > 4)
+			s->timer = 5;
+	printf(",\n\t\"timer\": \"(%s,%s,%d)\"",
+	ss_timer_name[s->timer], print_ms_timer(s->timeout), s->retrans);
+}
+
+static void sock_state_json_fmt(struct sockstat *s, const char **sstate_name,
+			const char *sock_name, int netid_width,
+			int state_width)
+{
+	char eol[] = ",\n";
+
+	if (netid_width)
+		printf("\n\t\"Netid\": \"%s\"%s", sock_name, eol);
+
+	if (state_width) {
+		printf("\n\t\"State\": ");
+		printf("\"%s\"", sstate_name[s->state]);
+		printf("%s", eol);
+	}
+
+	printf("\n\t\"Recv-Q\": %d%s", s->rq, eol);
+	printf("\n\t\"Send-Q\": %d", s->wq);
+}
+
+static void sock_details_json_fmt(struct sockstat *s, int type, unsigned groups,
+			unsigned long long cb)
+{
+	if (type == GENERIC_DETAIL && s->uid)
+		printf(",\n\t\"uid\": %u", s->uid);
+	if (type == GENERIC_DETAIL)
+		printf(",\n\t\"ino\": %u", s->ino);
+	printf(",\n\t\"sk\": \"%llx\"", s->sk);
+
+	if (type == NETLINK_DETAIL) {
+		printf(",\n\t\"cb\": \"%llx\"", cb);
+		printf(",\n\t\"groups=0x\": \"%08x\"", groups);
+	}
+}
+
+static void sock_addr_json_fmt(const char *addr, int addr_len, char *delim,
+			int port_len, const char *port, const char *ifname,
+			const char *peer_kind)
+{
+	char indent2[] = "\t\t";
+
+	printf("\n%s\"%s\": {\n", indent2, peer_kind);
+
+	char *indent3 = "\t\t\t";
+
+	printf("%s\"addr\": \"%s\",\n", indent3, addr);
+	printf("%s\"interface\": \"%s\"", indent3, ifname);
+	
+
+	print_serv_or_port(indent3, (char *)port);
+
+	printf("%s}", indent2);
+	if (strcmp(peer_kind, "remote") == 0)
+		printf("\n\t");
+	else
+		printf(",\n");
+}
+
+static void sock_users_json_fmt(char *out)
+{
+	make_userout_valid(out);
+
+	printf(",\n\t\"users\": \"%s\"", out);
+}
+
+static void sock_summary_json_fmt(struct ssummary *s, struct snmpstat *sn,
+			struct slabstat *slabstat, int has_succ)
+{
+
+	char eol[] = ",\n";
+	char eol2[] = "\n";
+	char indent3[] = "\t\t\t";
+
+	printf("\"summary\": {\n");
+	printf("\t\"total\": %d%s", s->socks, eol);
+	printf("\t\"kernel\": %d%s", slabstat->socks, eol);
+
+	printf("\t\"TCP\": {%s", eol2);
+	printf("\t\t\"total\": %d%s",
+	s->tcp_total + slabstat->tcp_syns + s->tcp_tws, eol);
+	printf("\t\t\"estab\": %d%s", sn->tcp_estab, eol);
+	printf("\t\t\"closed\": %d%s",
+	s->tcp_total - (s->tcp4_hashed + s->tcp6_hashed - s->tcp_tws),
+	eol);
+	printf("\t\t\"orphaned\": %d%s", s->tcp_orphans, eol);
+	printf("\t\t\"synrecv\": %d%s", slabstat->tcp_syns, eol);
+	printf("\t\t\"timewait\": \"%d/%d\"%s",
+	s->tcp_tws, slabstat->tcp_tws, eol);
+	printf("\t\t\"ports\": %d%s", slabstat->tcp_ports, eol2);
+	printf("\t}%s", eol);
+
+	printf("\t\"trans_over_net_prop\": {%s", eol2);
+	printf("\t\t\"*\": {%s", eol2);
+	printf("%s\"Total\": %d%s", indent3, slabstat->socks, eol);
+	printf("%s\"IP\": \"%s\"%s", indent3, "-", eol);
+	printf("%s\"IPv6\": \"%s\"%s", indent3, "-", eol2);
+	printf("\t\t}%s", eol);
+
+	printf("\t\t\"RAW\": {%s", eol2);
+	printf("%s\"Total\": %d%s", indent3, s->raw4 + s->raw6, eol);
+	printf("%s\"IP\": %d%s", indent3, s->raw4, eol);
+	printf("%s\"IPv6\": %d%s", indent3, s->raw6, eol2);
+	printf("\t\t}%s", eol);
+
+	printf("\t\t\"UDP\": {%s", eol2);
+	printf("%s\"Total\": %d%s", indent3, s->udp4 + s->udp6, eol);
+	printf("%s\"IP\": %d%s", indent3, s->udp4, eol);
+	printf("%s\"IPv6\": %d%s", indent3, s->udp6, eol2);
+	printf("\t\t}%s", eol);
+
+	printf("\t\t\"TCP\": {%s", eol2);
+	printf("%s\"Total\": %d%s",
+	indent3, s->tcp4_hashed + s->tcp6_hashed, eol);
+	printf("%s\"IP\": %d%s", indent3, s->tcp4_hashed, eol);
+	printf("%s\"IPv6\": %d%s", indent3, s->tcp6_hashed, eol2);
+	printf("\t\t}%s", eol);
+
+	printf("\t\t\"INET\": {%s", eol2);
+	printf("%s\"Total\": %d%s", indent3,
+	s->raw4 + s->udp4 + s->tcp4_hashed + s->raw6 + s->udp6 +
+	s->tcp6_hashed, eol);
+	printf("%s\"IP\": %d%s", indent3, s->raw4 + s->udp4 + s->tcp4_hashed,
+	eol);
+	printf("%s\"IPv6\": %d%s", indent3, s->raw6 + s->udp6 + s->tcp6_hashed,
+	eol2);
+	printf("\t\t}%s", eol);
+
+	printf("\t\t\"FRAG\": {%s", eol2);
+	printf("%s\"Total\": %d%s", indent3, s->frag4 + s->frag6, eol);
+	printf("%s\"IP\": %d%s", indent3, s->frag4, eol);
+	printf("%s\"IPv6\": %d%s", indent3, s->frag6, eol2);
+	printf("\t\t}%s", eol2);
+	printf("\t}%s", "\n");
+
+	printf("}\n");
+}
+
+static void sock_conn_json_fmt(unsigned char mask)
+{
+	printf(",\n\t\"shutdown\": \"%c-%c\"", mask & 1 ? '-' : '<',
+	mask & 2 ? '-' : '>');
+}
+
+static void mem_json_fmt(const struct inet_diag_meminfo *minfo)
+{
+	printf(",\n\t\"mem\": \"(r%u,w%u,f%u,t%u)\",\n",
+	minfo->idiag_rmem,
+	minfo->idiag_wmem, minfo->idiag_fmem, minfo->idiag_tmem);
+}
+
+static void skmem_json_fmt(const __u32 *skmeminfo, struct rtattr **tb,
+		int attrtype)
+{
+	printf(",\n\t\"skmem\": \"(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
+	skmeminfo[SK_MEMINFO_RMEM_ALLOC],
+	skmeminfo[SK_MEMINFO_RCVBUF],
+	skmeminfo[SK_MEMINFO_WMEM_ALLOC],
+	skmeminfo[SK_MEMINFO_SNDBUF],
+	skmeminfo[SK_MEMINFO_FWD_ALLOC],
+	skmeminfo[SK_MEMINFO_WMEM_QUEUED], skmeminfo[SK_MEMINFO_OPTMEM]);
+	if (RTA_PAYLOAD(tb[attrtype]) >=
+	(SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
+		printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
+	printf(")\"");
+}
+
+static void bpf_filter_json_fmt(struct sock_filter *fil, int num)
+{
+	printf(",\n\t\"bpf filter\": \"(%d):", num);
+	while (num) {
+		printf("0x%02x %u %u %u,", fil->code, fil->jt, fil->jf, fil->k);
+		num--;
+		fil++;
+	}
+	printf("\"\n");
+}
+
+static void opt_json_fmt(char *opt)
+{
+	printf(",\n\t\t\"opt\": \"%s\",\n", opt);
+}
+
+static void proc_json_fmt(int serv_width, char *pid_ctx)
+{
+	printf(",\n");
+	if (pid_ctx != NULL) {
+		printf("\t\"proc_ctx\": \"%-s\" ", pid_ctx);
+		free(pid_ctx);
+	} else {
+		printf("\t\"proc_ctx\": \"%-s\" ", "unavailable");
+	}
+}
+
+static void packet_show_ring_json_fmt(struct packet_diag_ring *ring)
+{
+	printf("\n\"blk_size\": \"%d\",\n", ring->pdr_block_size);
+	printf("\"blk_nr\" : \"%d\",\n", ring->pdr_block_nr);
+	printf("\"frm_size\" : \"%d\",\n", ring->pdr_frame_size);
+	printf("\"frm_nr\" : \"%d\",\n", ring->pdr_frame_nr);
+	printf("\"tmo\" : \"%d\",\n", ring->pdr_retire_tmo);
+	printf("\"features_0x\" : \"%x\"\n", ring->pdr_features);
+}
+
+const struct fmt_op_hub json_output_op = {
+	.tcp_stats_fmt = tcp_stats_json_fmt,
+	.tcp_timer_fmt = tcp_timer_json_fmt,
+	.sock_state_fmt = sock_state_json_fmt,
+	.sock_details_fmt = sock_details_json_fmt,
+	.sock_addr_fmt = sock_addr_json_fmt,
+	.sock_users_fmt = sock_users_json_fmt,
+	.sock_summary_fmt = sock_summary_json_fmt,
+	.sock_conn_fmt = sock_conn_json_fmt,
+	.mem_fmt = mem_json_fmt,
+	.skmem_fmt = skmem_json_fmt,
+	.bpf_filter_fmt = bpf_filter_json_fmt,
+	.opt_fmt = opt_json_fmt,
+	.proc_fmt = proc_json_fmt,
+	.packet_show_ring_fmt = packet_show_ring_json_fmt,
+};
diff --git a/misc/ss_json_fmt.h b/misc/ss_json_fmt.h
new file mode 100644
index 0000000..cbd26f1
--- /dev/null
+++ b/misc/ss_json_fmt.h
@@ -0,0 +1,24 @@
+#ifndef SS_JSON_FMT_H
+#define SS_JSON_FMT_H
+
+#include <linux/inet_diag.h>
+#include <linux/pkt_sched.h>
+#include <linux/filter.h>
+#include "ss_types.h"
+
+extern int json_output;
+extern int resolve_services;
+extern int show_options;
+extern int show_details;
+extern int show_users;
+extern int show_mem;
+extern int show_tcpinfo;
+extern int show_bpf;
+extern int show_proc_ctx;
+extern int show_sock_ctx;
+extern struct filter ss_current_filter;
+
+/*generic auxiliary mechanism for json related dangling delimiter issues*/
+void res_json_fmt_branch(int pred, char bound);
+
+#endif				/* SS_JSON_FMT_H */
diff --git a/misc/ss_out_fmt.c b/misc/ss_out_fmt.c
new file mode 100644
index 0000000..e17d898
--- /dev/null
+++ b/misc/ss_out_fmt.c
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include "ss_out_fmt.h"
+const struct fmt_op_hub *fmt_op_hub[] = {
+	/*human readble */
+	&hr_output_op,
+	/*json */
+	&json_output_op
+};
+
+
+
+char *sprint_bw(char *buf, double bw)
+{
+	if (bw > 1000000.)
+		sprintf(buf, "%.1fM", bw / 1000000.);
+	else if (bw > 1000.)
+		sprintf(buf, "%.1fK", bw / 1000.);
+	else
+		sprintf(buf, "%g", bw);
+
+	return buf;
+}
+
+char *print_ms_timer(int timeout)
+{
+	static char buf[64];
+	int secs, msecs, minutes;
+
+	if (timeout < 0)
+		timeout = 0;
+	secs = timeout / 1000;
+	minutes = secs / 60;
+	secs = secs % 60;
+	msecs = timeout % 1000;
+	buf[0] = 0;
+	if (minutes) {
+		msecs = 0;
+		snprintf(buf, sizeof(buf) - 16, "%dmin", minutes);
+		if (minutes > 9)
+			secs = 0;
+	}
+	if (secs) {
+		if (secs > 9)
+			msecs = 0;
+		sprintf(buf + strlen(buf), "%d%s", secs, msecs ? "." : "sec");
+	}
+	if (msecs)
+		sprintf(buf + strlen(buf), "%03dms", msecs);
+	return buf;
+}
+
+void tcp_stats_fmt(struct tcpstat *s)
+{
+	fmt_op_hub[fmt_type]->tcp_stats_fmt(s);
+}
+
+void tcp_timer_fmt(struct tcpstat *s)
+{
+	fmt_op_hub[fmt_type]->tcp_timer_fmt(s);
+}
+
+void sock_state_fmt(struct sockstat *s, const char **sstate_name,
+		const char *sock_name, int netid_width, int state_width)
+{
+	fmt_op_hub[fmt_type]->sock_state_fmt(s, sstate_name, sock_name,
+					netid_width, state_width);
+}
+
+void sock_details_fmt(struct sockstat *s, int type,
+		unsigned groups, unsigned long long cb)
+{
+	fmt_op_hub[fmt_type]->sock_details_fmt(s, type, groups, cb);
+}
+
+void sock_addr_fmt(const char *addr, int addr_len, char *delim,
+		int port_len, const char *port, const char *ifname,
+		const char *peer_kind)
+{
+	fmt_op_hub[fmt_type]->sock_addr_fmt(addr, addr_len,
+					delim, port_len, port, ifname,
+					peer_kind);
+}
+
+void sock_users_fmt(char *out)
+{
+	fmt_op_hub[fmt_type]->sock_users_fmt(out);
+}
+
+void sock_summary_fmt(struct ssummary *s, struct snmpstat *sn,
+		struct slabstat *slabstat, int has_succ)
+{
+	fmt_op_hub[fmt_type]->sock_summary_fmt(s, sn, slabstat, has_succ);
+}
+
+void sock_conn_fmt(unsigned char mask)
+{
+	fmt_op_hub[fmt_type]->sock_conn_fmt(mask);
+}
+
+void mem_fmt(const struct inet_diag_meminfo *minfo)
+{
+	fmt_op_hub[fmt_type]->mem_fmt(minfo);
+}
+
+void skmem_fmt(const __u32 *skmeminfo, struct rtattr **tb, int attrtype)
+{
+	fmt_op_hub[fmt_type]->skmem_fmt(skmeminfo, tb, attrtype);
+}
+
+void bpf_filter_fmt(struct sock_filter *f, int num)
+{
+	fmt_op_hub[fmt_type]->bpf_filter_fmt(f, num);
+}
+
+void opt_fmt(char *opt)
+{
+	fmt_op_hub[fmt_type]->opt_fmt(opt);
+}
+
+void proc_fmt(int serv_width, char *pid_ctx)
+{
+	fmt_op_hub[fmt_type]->proc_fmt(serv_width, pid_ctx);
+}
+void packet_show_ring_fmt(struct packet_diag_ring *ring)
+{
+	fmt_op_hub[fmt_type]->packet_show_ring_fmt(ring);
+}
diff --git a/misc/ss_out_fmt.h b/misc/ss_out_fmt.h
new file mode 100644
index 0000000..b74f668
--- /dev/null
+++ b/misc/ss_out_fmt.h
@@ -0,0 +1,82 @@
+#ifndef SS_OUT_FMT_H
+#define SS_OUT_FMT_H
+
+#include "ss_hr_fmt.h"
+#include "ss_json_fmt.h"
+#include "ss_types.h"
+#include <linux/inet_diag.h>
+#include <linux/pkt_sched.h>
+#include <linux/filter.h>
+#include <linux/netdevice.h>
+#include <linux/packet_diag.h>
+
+#define GENERIC_DETAIL 0
+#define NETLINK_DETAIL 1
+
+#define STATIC_ASSERT(COND, MSG) char STATIC_ASSERT##MSG[(COND) ? 1 : -1]
+/*when extending the tcp fmt handler,
+ *you have to pass the last cond of the tcp_stats
+ *struct as sentinel to this macro to ensure compilability
+ * of ss: this enforces a symmetrical extension of the individual
+ * formatting handlers */
+#define CHECK_FMT_ADAPT(SENTINEL, BEGIN, MSG) \
+	STATIC_ASSERT((((void *)&SENTINEL - (void *)BEGIN) + sizeof(SENTINEL)) \
+	/ sizeof(*BEGIN), MSG)
+
+
+extern int json_output;
+extern enum out_fmt_type fmt_type;
+extern const struct fmt_op_hub hr_output_op;
+extern const struct fmt_op_hub json_output_op;
+extern const char *ss_timer_name[];
+
+enum out_fmt_type { FMT_HR, FMT_JSON };
+
+struct fmt_op_hub {
+	void (*tcp_stats_fmt)(struct tcpstat *s);
+	void (*tcp_timer_fmt)(struct tcpstat *s);
+	void (*sock_state_fmt)(struct sockstat *s, const char **sstate_name,
+				const char *sock_name, int netid_width,
+				int state_width);
+	void (*sock_details_fmt)(struct sockstat *s, int type,
+				unsigned groups, unsigned long long cb);
+	void (*sock_addr_fmt)(const char *addr, int addr_len, char *delim,
+			int port_len, const char *port,
+			const char *ifname, const char *peer_kind);
+	void (*sock_users_fmt)(char *out);
+	void (*sock_summary_fmt)(struct ssummary *s, struct snmpstat *sn,
+				struct slabstat *slabstat, int has_succ);
+	void (*sock_conn_fmt)(unsigned char mask);
+	void (*mem_fmt)(const struct inet_diag_meminfo *minfo);
+	void (*skmem_fmt)(const __u32 *skmeminfo, struct rtattr **tb,
+			int attrtype);
+	void (*bpf_filter_fmt)(struct sock_filter *f, int num);
+	void (*opt_fmt)(char *opt);
+	void (*proc_fmt)(int serv_width, char *pid_ctx);
+	void (*packet_show_ring_fmt)(struct packet_diag_ring *ring);
+};
+
+void tcp_stats_fmt(struct tcpstat *s);
+void tcp_timer_fmt(struct tcpstat *s);
+void sock_state_fmt(struct sockstat *s, const char **sstate_name,
+		const char *sock_name, int netid_width, int state_width);
+void sock_details_fmt(struct sockstat *s, int type,
+		unsigned groups, unsigned long long cb);
+void sock_addr_fmt(const char *addr, int addr_len, char *delim, int port_len,
+		const char *port, const char *ifname, const char *peer_kind);
+void sock_users_fmt(char *out);
+void sock_summary_fmt(struct ssummary *s, struct snmpstat *sn,
+		struct slabstat *slabstat, int has_succ);
+void sock_conn_fmt(unsigned char mask);
+void mem_fmt(const struct inet_diag_meminfo *minfo);
+void skmem_fmt(const __u32 *skmeminfo, struct rtattr **tb, int attrtype);
+void bpf_filter_fmt(struct sock_filter *f, int num);
+void opt_fmt(char *opt);
+void proc_fmt(int serv_width, char *pid_ctx);
+void packet_show_ring_fmt(struct packet_diag_ring *ring);
+
+/*unisonly utilized formatting parts*/
+char *sprint_bw(char *buf, double bw);
+char *print_ms_timer(int timeout);
+
+#endif				/* SS_OUT_FMT_H */
-- 
1.9.1

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

* [PATCH 03/10] ss: removed obsolet fmt functions
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 02/10] ss: created formatters for json and hr Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 04/10] ss: prepare timer for output handler usage Matthias Tafelmeier
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

Those functions are obsoleted since the new fmt handler mechanism
subsumes their tasks. Rendundancy would be contradictory to
the new mechanism.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 190 --------------------------------------------------------------
 1 file changed, 190 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 3d31b81..e241b2f 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -647,43 +647,6 @@ static const char *sstate_namel[] = {
 	[SS_CLOSING] = "closing",
 };
 
-static void sock_state_print(struct sockstat *s, const char *sock_name)
-{
-	if (netid_width)
-		printf("%-*s ", netid_width, sock_name);
-	if (state_width)
-		printf("%-*s ", state_width, sstate_name[s->state]);
-
-	printf("%-6d %-6d ", s->rq, s->wq);
-}
-
-static void sock_details_print(struct sockstat *s)
-{
-	if (s->uid)
-		printf(" uid:%u", s->uid);
-
-	printf(" ino:%u", s->ino);
-	printf(" sk:%llx", s->sk);
-}
-
-static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
-		int port_len, const char *port, const char *ifname)
-{
-	if (ifname) {
-		printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
-				port_len, port);
-	}
-	else {
-		printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
-	}
-}
-
-static void sock_addr_print(const char *addr, char *delim, const char *port,
-		const char *ifname)
-{
-	sock_addr_print_width(addr_width, addr, delim, serv_width, port, ifname);
-}
-
 static const char *tmr_name[] = {
 	"off",
 	"on",
@@ -693,33 +656,6 @@ static const char *tmr_name[] = {
 	"unknown"
 };
 
-static const char *print_ms_timer(int timeout)
-{
-	static char buf[64];
-	int secs, msecs, minutes;
-	if (timeout < 0)
-		timeout = 0;
-	secs = timeout/1000;
-	minutes = secs/60;
-	secs = secs%60;
-	msecs = timeout%1000;
-	buf[0] = 0;
-	if (minutes) {
-		msecs = 0;
-		snprintf(buf, sizeof(buf)-16, "%dmin", minutes);
-		if (minutes > 9)
-			secs = 0;
-	}
-	if (secs) {
-		if (secs > 9)
-			msecs = 0;
-		sprintf(buf+strlen(buf), "%d%s", secs, msecs ? "." : "sec");
-	}
-	if (msecs)
-		sprintf(buf+strlen(buf), "%03dms", msecs);
-	return buf;
-}
-
 struct scache *rlist;
 
 static void init_service_resolver(void)
@@ -1482,122 +1418,6 @@ static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
 	return 0;
 }
 
-static char *sprint_bw(char *buf, double bw)
-{
-	if (bw > 1000000.)
-		sprintf(buf,"%.1fM", bw / 1000000.);
-	else if (bw > 1000.)
-		sprintf(buf,"%.1fK", bw / 1000.);
-	else
-		sprintf(buf, "%g", bw);
-
-	return buf;
-}
-
-static void tcp_stats_print(struct tcpstat *s)
-{
-	char b1[64];
-
-	if (s->has_ts_opt)
-		printf(" ts");
-	if (s->has_sack_opt)
-		printf(" sack");
-	if (s->has_ecn_opt)
-		printf(" ecn");
-	if (s->has_ecnseen_opt)
-		printf(" ecnseen");
-	if (s->has_fastopen_opt)
-		printf(" fastopen");
-	if (s->cong_alg[0])
-		printf(" %s", s->cong_alg);
-	if (s->has_wscale_opt)
-		printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
-	if (s->rto)
-		printf(" rto:%g", s->rto);
-	if (s->backoff)
-		printf(" backoff:%u", s->backoff);
-	if (s->rtt)
-		printf(" rtt:%g/%g", s->rtt, s->rttvar);
-	if (s->ato)
-		printf(" ato:%g", s->ato);
-
-	if (s->qack)
-		printf(" qack:%d", s->qack);
-	if (s->qack & 1)
-		printf(" bidir");
-
-	if (s->mss)
-		printf(" mss:%d", s->mss);
-	if (s->cwnd)
-		printf(" cwnd:%d", s->cwnd);
-	if (s->ssthresh)
-		printf(" ssthresh:%d", s->ssthresh);
-
-	if (s->bytes_acked)
-		printf(" bytes_acked:%llu", s->bytes_acked);
-	if (s->bytes_received)
-		printf(" bytes_received:%llu", s->bytes_received);
-	if (s->segs_out)
-		printf(" segs_out:%u", s->segs_out);
-	if (s->segs_in)
-		printf(" segs_in:%u", s->segs_in);
-
-	if (s->dctcp && s->dctcp->enabled) {
-		struct dctcpstat *dctcp = s->dctcp;
-
-		printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
-				dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
-				dctcp->ab_tot);
-	} else if (s->dctcp) {
-		printf(" dctcp:fallback_mode");
-	}
-
-	if (s->send_bps)
-		printf(" send %sbps", sprint_bw(b1, s->send_bps));
-	if (s->lastsnd)
-		printf(" lastsnd:%u", s->lastsnd);
-	if (s->lastrcv)
-		printf(" lastrcv:%u", s->lastrcv);
-	if (s->lastack)
-		printf(" lastack:%u", s->lastack);
-
-	if (s->pacing_rate) {
-		printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
-		if (s->pacing_rate_max)
-				printf("/%sbps", sprint_bw(b1,
-							s->pacing_rate_max));
-	}
-
-	if (s->unacked)
-		printf(" unacked:%u", s->unacked);
-	if (s->retrans || s->retrans_total)
-		printf(" retrans:%u/%u", s->retrans, s->retrans_total);
-	if (s->lost)
-		printf(" lost:%u", s->lost);
-	if (s->sacked && s->ss.state != SS_LISTEN)
-		printf(" sacked:%u", s->sacked);
-	if (s->fackets)
-		printf(" fackets:%u", s->fackets);
-	if (s->reordering != 3)
-		printf(" reordering:%d", s->reordering);
-	if (s->rcv_rtt)
-		printf(" rcv_rtt:%g", s->rcv_rtt);
-	if (s->rcv_space)
-		printf(" rcv_space:%d", s->rcv_space);
-}
-
-static void tcp_timer_print(struct tcpstat *s)
-{
-	if (s->timer) {
-		if (s->timer > 4)
-			s->timer = 5;
-		printf(" timer:(%s,%s,%d)",
-				tmr_name[s->timer],
-				print_ms_timer(s->timeout),
-				s->retrans);
-	}
-}
-
 static int tcp_show_line(char *line, const struct filter *f, int family)
 {
 	int rto = 0, ato = 0;
@@ -2692,16 +2512,6 @@ static int packet_stats_print(struct sockstat *s, const struct filter *f)
 	return 0;
 }
 
-static void packet_show_ring(struct packet_diag_ring *ring)
-{
-	printf("blk_size:%d", ring->pdr_block_size);
-	printf(",blk_nr:%d", ring->pdr_block_nr);
-	printf(",frm_size:%d", ring->pdr_frame_size);
-	printf(",frm_nr:%d", ring->pdr_frame_nr);
-	printf(",tmo:%d", ring->pdr_retire_tmo);
-	printf(",features:0x%x", ring->pdr_features);
-}
-
 static int packet_show_sock(const struct sockaddr_nl *addr,
 		struct nlmsghdr *nlh, void *arg)
 {
-- 
1.9.1

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

* [PATCH 04/10] ss: prepare timer for output handler usage
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (2 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 03/10] ss: removed obsolet fmt functions Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 05/10] ss: framed skeleton for json output in ss Matthias Tafelmeier
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

Minor preparation Patch

Renamed, and exported timer to not have to pass it as a function local
parameter argument.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/misc/ss.c b/misc/ss.c
index e241b2f..1b3ef90 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -647,7 +647,7 @@ static const char *sstate_namel[] = {
 	[SS_CLOSING] = "closing",
 };
 
-static const char *tmr_name[] = {
+const char *ss_timer_name[] = {
 	"off",
 	"on",
 	"keepalive",
-- 
1.9.1

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

* [PATCH 05/10] ss: framed skeleton for json output in ss
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (3 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 04/10] ss: prepare timer for output handler usage Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 06/10] ss: replaced old output mechanisms with fmt handlers interfaces Matthias Tafelmeier
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

This patch just adds the --json flag to ss. Also it ensures proper
stats components bracketization – that goes for ex. TCP, UDP, NETLINK etc.

Moreover, this patch prevents human readable headers to be printed. The
first element flag ensures, that every first output json container
element is treated specially, while all the others are treated equally.
That is, only the first one does not print a coma ahead of itself. The
rest does. This mechanism ensures the correct coma setting as demaned by
the spec. Illustration in the following:

PSEUDOCODE:

{ >>>> no comma
	{first }
>>>>	,
	{sec}
>>>>	,
	{third}
	.
	.
	.
}

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 157 insertions(+), 43 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 1b3ef90..f563710 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -34,6 +34,9 @@
 #include "libnetlink.h"
 #include "namespace.h"
 #include "SNAPSHOT.h"
+#include "ss_out_fmt.h"
+#include "ss_json_fmt.h"
+#include "ss_types.h"
 
 #include <linux/tcp.h>
 #include <linux/sock_diag.h>
@@ -101,6 +104,7 @@ 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 json_output = 0;
 
 int netid_width;
 int state_width;
@@ -714,7 +718,6 @@ static int is_ephemeral(int port)
 	return (port >= ip_local_port_min && port<= ip_local_port_max);
 }
 
-
 static const char *__resolve_service(int port)
 {
 	struct scache *c;
@@ -3064,6 +3067,9 @@ static int print_summary(void)
 
 	printf("\n");
 
+	if (json_output && has_successor)
+		printf(",\n");
+
 	return 0;
 }
 
@@ -3090,6 +3096,7 @@ static void _usage(FILE *dest)
 "   -z, --contexts      display process and socket SELinux security contexts\n"
 "   -N, --net           switch to the specified network namespace name\n"
 "\n"
+"   -j, --json          format output in JSON\n"
 "   -4, --ipv4          display only IP version 4 sockets\n"
 "   -6, --ipv6          display only IP version 6 sockets\n"
 "   -0, --packet        display PACKET sockets\n"
@@ -3189,6 +3196,7 @@ static const struct option long_opts[] = {
 	{ "help", 0, 0, 'h' },
 	{ "context", 0, 0, 'Z' },
 	{ "contexts", 0, 0, 'z' },
+	{ "json", 0, 0, 'j' },
 	{ "net", 1, 0, 'N' },
 	{ 0 }
 
@@ -3204,7 +3212,7 @@ int main(int argc, char *argv[])
 	int ch;
 	int state_filter = 0;
 
-	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:",
+	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:j",
 				 long_opts, NULL)) != EOF) {
 		switch(ch) {
 		case 'n':
@@ -3383,6 +3391,10 @@ int main(int argc, char *argv[])
 			if (netns_switch(optarg))
 				exit(1);
 			break;
+		case 'j':
+			fmt_type = FMT_JSON;
+			json_output = 1;
+			break;
 		case 'h':
 		case '?':
 			help();
@@ -3464,11 +3476,34 @@ int main(int argc, char *argv[])
 				exit(-1);
 			}
 		}
+		printf("\"TCP\": [\n");
 		inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
+		res_json_fmt_branch(current_filter.dbs & (1<<NETLINK_DB) ||
+				current_filter.dbs & PACKET_DBM ||
+				current_filter.dbs & UNIX_DBM ||
+				current_filter.dbs & (1<<RAW_DB) ||
+				current_filter.dbs & (1<<UDP_DB) ||
+				current_filter.dbs & (1<<TCP_DB) ||
+				current_filter.dbs & (1<<DCCP_DB), ']');
 		fflush(dump_fp);
 		exit(0);
 	}
 
+	if (do_summary) {
+		print_summary(current_filter.dbs & PACKET_DBM ||
+				current_filter.dbs & UNIX_DBM ||
+				current_filter.dbs & (1<<RAW_DB) ||
+				current_filter.dbs & (1<<UDP_DB) ||
+				current_filter.dbs & (1<<TCP_DB) ||
+				current_filter.dbs & (1<<DCCP_DB));
+		if (do_default && argc == 0) {
+			if (json_output) {
+				printf("}\n");
+			}
+			exit(0);
+		}
+	}
+
 	if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
 		usage();
 
@@ -3490,62 +3525,141 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	addrp_width = screen_width;
-	addrp_width -= netid_width+1;
-	addrp_width -= state_width+1;
-	addrp_width -= 14;
+	if (!json_output) {
+
+		addrp_width = screen_width;
+		addrp_width -= netid_width + 1;
+		addrp_width -= state_width + 1;
+		addrp_width -= 14;
+
+		if (addrp_width & 1) {
+			if (netid_width)
+				netid_width++;
+			else if (state_width)
+				state_width++;
+		}
+
+		addrp_width /= 2;
+		addrp_width--;
+
+		serv_width = resolve_services ? 7 : 5;
+
+		if (addrp_width < 15 + serv_width + 1)
+			addrp_width = 15 + serv_width + 1;
 
-	if (addrp_width&1) {
+		addr_width = addrp_width - serv_width - 1;
 		if (netid_width)
-			netid_width++;
-		else if (state_width)
-			state_width++;
-	}
+			printf("%-*s ", netid_width, "Netid");
+		if (state_width)
+			printf("%-*s ", state_width, "State");
+		printf("%-6s %-6s ", "Recv-Q", "Send-Q");
+
+		/* Make enough space for the local/remote port field */
+		addr_width -= 13;
+		serv_width += 13;
 
-	addrp_width /= 2;
-	addrp_width--;
+		printf("%*s:%-*s %*s:%-*s\n",
+				addr_width, "Local Address", serv_width, "Port",
+				addr_width, "Peer Address", serv_width, "Port");
+	}
 
-	serv_width = resolve_services ? 7 : 5;
+	fflush(stdout);
 
-	if (addrp_width < 15+serv_width+1)
-		addrp_width = 15+serv_width+1;
+	if (current_filter.dbs & (1<<NETLINK_DB)) {
+		if (json_output) {
+			printf("\"NETLINK\": [\n");
+			netlink_show(&current_filter);
+			json_first_elem = 1;
+			res_json_fmt_branch(current_filter.dbs & PACKET_DBM ||
+					current_filter.dbs & UNIX_DBM ||
+					current_filter.dbs & (1<<RAW_DB) ||
+					current_filter.dbs & (1<<UDP_DB) ||
+					current_filter.dbs & (1<<TCP_DB) ||
+					current_filter.dbs & (1<<DCCP_DB), ']');
+		} else
+			netlink_show(&current_filter);
+	}
+	if (current_filter.dbs & PACKET_DBM) {
+		if (json_output) {
+			printf("\"PACKET\": [\n");
+			packet_show(&current_filter);
+			json_first_elem = 1;
+			res_json_fmt_branch(
+					current_filter.dbs & UNIX_DBM ||
+					current_filter.dbs & (1<<RAW_DB) ||
+					current_filter.dbs & (1<<UDP_DB) ||
+					current_filter.dbs & (1<<TCP_DB) ||
+					current_filter.dbs & (1<<DCCP_DB), ']');
+		} else
+			packet_show(&current_filter);
+	}
+	if (current_filter.dbs & UNIX_DBM) {
+		if (json_output) {
+			printf("\"UNIX\": [\n");
+			unix_show(&current_filter);
+			json_first_elem = 1;
+			res_json_fmt_branch(
+					current_filter.dbs & (1<<RAW_DB) ||
+					current_filter.dbs & (1<<UDP_DB) ||
+					current_filter.dbs & (1<<TCP_DB) ||
+					current_filter.dbs & (1<<DCCP_DB), ']');
 
-	addr_width = addrp_width - serv_width - 1;
+		} else
+			unix_show(&current_filter);
+	}
+	if (current_filter.dbs & (1<<RAW_DB)) {
+		if (json_output) {
+			printf("\"RAW\": [\n");
+			raw_show(&current_filter);
+			json_first_elem = 1;
+			res_json_fmt_branch(
+					current_filter.dbs & (1<<UDP_DB) ||
+					current_filter.dbs & (1<<TCP_DB) ||
+					current_filter.dbs & (1<<DCCP_DB), ']');
 
-	if (netid_width)
-		printf("%-*s ", netid_width, "Netid");
-	if (state_width)
-		printf("%-*s ", state_width, "State");
-	printf("%-6s %-6s ", "Recv-Q", "Send-Q");
+		} else
+			raw_show(&current_filter);
+	}
+	if (current_filter.dbs & (1<<UDP_DB)) {
+		if (json_output) {
+			printf("\"UDP\": [\n");
+			udp_show(&current_filter);
+			json_first_elem = 1;
+			res_json_fmt_branch(
+					current_filter.dbs & (1<<TCP_DB) ||
+					current_filter.dbs & (1<<DCCP_DB), ']');
 
-	/* Make enough space for the local/remote port field */
-	addr_width -= 13;
-	serv_width += 13;
+		} else
+			udp_show(&current_filter);
+	}
+	if (current_filter.dbs & (1<<TCP_DB)) {
+		if (json_output) {
+			printf("\"TCP\": [\n");
+			tcp_show(&current_filter, IPPROTO_TCP);
+			json_first_elem = 1;
+			res_json_fmt_branch(
+					current_filter.dbs & (1<<DCCP_DB), ']');
+		} else
+			tcp_show(&current_filter, IPPROTO_TCP);
+	}
+	if (current_filter.dbs & (1<<DCCP_DB)) {
+		if (json_output) {
+			printf("\"DCCP\": [\n");
+			tcp_show(&current_filter, IPPROTO_DCCP);
+			printf("]\n");
+		} else
+			tcp_show(&current_filter, IPPROTO_DCCP);
+	}
 
-	printf("%*s:%-*s %*s:%-*s\n",
-	       addr_width, "Local Address", serv_width, "Port",
-	       addr_width, "Peer Address", serv_width, "Port");
+	if (json_output) {
+		printf("}\n");
+	}
 
 	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)
-		packet_show(&current_filter);
-	if (current_filter.dbs & UNIX_DBM)
-		unix_show(&current_filter);
-	if (current_filter.dbs & (1<<RAW_DB))
-		raw_show(&current_filter);
-	if (current_filter.dbs & (1<<UDP_DB))
-		udp_show(&current_filter);
-	if (current_filter.dbs & (1<<TCP_DB))
-		tcp_show(&current_filter, IPPROTO_TCP);
-	if (current_filter.dbs & (1<<DCCP_DB))
-		tcp_show(&current_filter, IPPROTO_DCCP);
-
 	if (show_users || show_proc_ctx || show_sock_ctx)
 		user_ent_destroy();
 
-- 
1.9.1

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

* [PATCH 06/10] ss: replaced old output mechanisms with fmt handlers interfaces
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (4 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 05/10] ss: framed skeleton for json output in ss Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 07/10] ss: renaming and export of current_filter Matthias Tafelmeier
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

Now, since the fmt (json, hr) handlers are in place, all can be output via these
newly deviced code parts.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 332 +++++++++++++++++++++++++++++---------------------------------
 1 file changed, 153 insertions(+), 179 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index f563710..a760cf9 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -105,6 +105,7 @@ int show_sock_ctx = 0;
 int user_ent_hash_build_init = 0;
 int follow_events = 0;
 int json_output = 0;
+int json_first_elem = 1;
 
 int netid_width;
 int state_width;
@@ -113,6 +114,8 @@ int addr_width;
 int serv_width;
 int screen_width;
 
+enum out_fmt_type fmt_type = FMT_HR;
+
 static const char *TCP_PROTO = "tcp";
 static const char *UDP_PROTO = "udp";
 static const char *RAW_PROTO = "raw";
@@ -346,6 +349,16 @@ static FILE *ephemeral_ports_open(void)
 #define USER_ENT_HASH_SIZE	256
 struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
 
+static void json_print_opening(void)
+{
+	if (json_output && json_first_elem) {
+		json_first_elem = 0;
+		printf("{\n");
+	} else if (json_output) {
+		printf(",\n{\n");
+	}
+}
+
 static int user_ent_hashfn(unsigned int ino)
 {
 	int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
@@ -791,7 +804,8 @@ do_numeric:
 	return buf;
 }
 
-static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex)
+static void inet_addr_print(const inet_prefix * a, int port,
+			    unsigned int ifindex, char *peer_kind)
 {
 	char buf[1024];
 	const char *ap = buf;
@@ -819,8 +833,8 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex
 		est_len -= strlen(ifname) + 1;  /* +1 for percent char */
 	}
 
-	sock_addr_print_width(est_len, ap, ":", serv_width, resolve_service(port),
-			ifname);
+	sock_addr_fmt(ap, est_len, ":", serv_width, resolve_service(port),
+			ifname, peer_kind);
 }
 
 static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
@@ -1352,21 +1366,28 @@ static void inet_stats_print(struct sockstat *s, int protocol)
 {
 	char *buf = NULL;
 
-	sock_state_print(s, proto_name(protocol));
+	sock_state_fmt(s, sstate_name, proto_name(protocol),
+		       	netid_width, state_width);
 
-	inet_addr_print(&s->local, s->lport, s->iface);
-	inet_addr_print(&s->remote, s->rport, 0);
+	if (json_output) {
+		printf("\t,\"peers\": {\n");
+	}
+	inet_addr_print(&s->local, s->lport, s->iface, "local");
+	inet_addr_print(&s->remote, s->rport, 0, "remote");
+	if (json_output) {
+		printf("}");
+	}
 
 	if (show_proc_ctx || show_sock_ctx) {
 		if (find_entry(s->ino, &buf,
-				(show_proc_ctx & show_sock_ctx) ?
-				PROC_SOCK_CTX : PROC_CTX) > 0) {
-			printf(" users:(%s)", buf);
+			       (show_proc_ctx & show_sock_ctx) ?
+			       PROC_SOCK_CTX : PROC_CTX) > 0) {
+			sock_users_fmt(buf);
 			free(buf);
 		}
 	} else if (show_users) {
 		if (find_entry(s->ino, &buf, USERS) > 0) {
-			printf(" users:(%s)", buf);
+			sock_users_fmt(buf);
 			free(buf);
 		}
 	}
@@ -1470,16 +1491,16 @@ static int tcp_show_line(char *line, const struct filter *f, int family)
 	inet_stats_print(&s.ss, IPPROTO_TCP);
 
 	if (show_options)
-		tcp_timer_print(&s);
+		tcp_timer_fmt(&s);
 
 	if (show_details) {
-		sock_details_print(&s.ss);
+		sock_details_fmt(&s.ss, GENERIC_DETAIL, 0, 0);
 		if (opt[0])
-			printf(" opt:\"%s\"", opt);
+			opt_fmt(opt);
 	}
 
 	if (show_tcpinfo)
-		tcp_stats_print(&s);
+		tcp_stats_fmt(&s);
 
 	printf("\n");
 	return 0;
@@ -1523,31 +1544,14 @@ static void print_skmeminfo(struct rtattr *tb[], int attrtype)
 			const struct inet_diag_meminfo *minfo =
 				RTA_DATA(tb[INET_DIAG_MEMINFO]);
 
-			printf(" mem:(r%u,w%u,f%u,t%u)",
-					minfo->idiag_rmem,
-					minfo->idiag_wmem,
-					minfo->idiag_fmem,
-					minfo->idiag_tmem);
+			mem_fmt(minfo);
 		}
 		return;
 	}
 
 	skmeminfo = RTA_DATA(tb[attrtype]);
 
-	printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
-	       skmeminfo[SK_MEMINFO_RMEM_ALLOC],
-	       skmeminfo[SK_MEMINFO_RCVBUF],
-	       skmeminfo[SK_MEMINFO_WMEM_ALLOC],
-	       skmeminfo[SK_MEMINFO_SNDBUF],
-	       skmeminfo[SK_MEMINFO_FWD_ALLOC],
-	       skmeminfo[SK_MEMINFO_WMEM_QUEUED],
-	       skmeminfo[SK_MEMINFO_OPTMEM]);
-
-	if (RTA_PAYLOAD(tb[attrtype]) >=
-		(SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
-		printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
-
-	printf(")");
+	skmem_fmt(skmeminfo, tb, attrtype);
 }
 
 #define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
@@ -1660,8 +1664,11 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
 		s.bytes_received = info->tcpi_bytes_received;
 		s.segs_out = info->tcpi_segs_out;
 		s.segs_in = info->tcpi_segs_in;
-		tcp_stats_print(&s);
-		free(s.dctcp);
+		tcp_stats_fmt(&s);
+		if (s.dctcp)
+			free(s.dctcp);
+		if (s.cong_alg)
+			free(s.cong_alg);
 	}
 }
 
@@ -1685,6 +1692,8 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
 	s.iface		= r->id.idiag_if;
 	s.sk		= cookie_sk_get(&r->id.idiag_cookie[0]);
 
+	json_print_opening();
+
 	if (s.local.family == AF_INET) {
 		s.local.bytelen = s.remote.bytelen = 4;
 	} else {
@@ -1708,29 +1717,29 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
 		t.timer = r->idiag_timer;
 		t.timeout = r->idiag_expires;
 		t.retrans = r->idiag_retrans;
-		tcp_timer_print(&t);
+		tcp_timer_fmt(&t);
 	}
 
 	if (show_details) {
-		sock_details_print(&s);
-		if (s.local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) {
-			unsigned char v6only;
-			v6only = *(__u8 *)RTA_DATA(tb[INET_DIAG_SKV6ONLY]);
-			printf(" v6only:%u", v6only);
-		}
+		sock_details_fmt(&s, GENERIC_DETAIL, 0, 0);
 		if (tb[INET_DIAG_SHUTDOWN]) {
 			unsigned char mask;
 			mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
-			printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+			sock_conn_fmt(mask);
 		}
 	}
 
 	if (show_mem || show_tcpinfo) {
-		printf("\n\t");
+		if (!json_output)
+			printf("\n\t");
 		tcp_show_info(nlh, r, tb);
 	}
 
-	printf("\n");
+	if (json_output)
+		printf("}\n");
+	else
+		printf("\n");
+
 	return 0;
 }
 
@@ -2081,7 +2090,10 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
 	inet_stats_print(&s, dg_proto == UDP_PROTO ? IPPROTO_UDP : 0);
 
 	if (show_details && opt[0])
-		printf(" opt:\"%s\"", opt);
+		opt_fmt(opt);
+
+	if (json_output)
+		printf("}");
 
 	printf("\n");
 	return 0;
@@ -2258,27 +2270,36 @@ static void unix_stats_print(struct sockstat *list, struct filter *f)
 				continue;
 		}
 
-		sock_state_print(s, unix_netid_name(s->type));
+		sock_state_fmt(s, sstate_name,
+				unix_netid_name(s->type), netid_width, state_width);
 
-		sock_addr_print(s->name ?: "*", " ",
-				int_to_str(s->lport, port_name), NULL);
-		sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
-				NULL);
+		if (json_output) {
+			printf("\t,\"peers\": {\n");
+		}
+		sock_addr_fmt(s->name ?: "*", addr_width, " ", serv_width,
+				int_to_str(s->lport, port_name),
+				NULL, "local");
+		sock_addr_fmt(peer, addr_width, " ", serv_width,
+				int_to_str(s->rport, port_name),
+				NULL, "remote");
+		if (json_output)
+			printf("}\n");
 
 		if (show_proc_ctx || show_sock_ctx) {
 			if (find_entry(s->ino, &ctx_buf,
-					(show_proc_ctx & show_sock_ctx) ?
-					PROC_SOCK_CTX : PROC_CTX) > 0) {
-				printf(" users:(%s)", ctx_buf);
+				       (show_proc_ctx & show_sock_ctx) ?
+				       PROC_SOCK_CTX : PROC_CTX) > 0) {
+				sock_users_fmt(ctx_buf);
 				free(ctx_buf);
 			}
 		} else if (show_users) {
 			if (find_entry(s->ino, &ctx_buf, USERS) > 0) {
-				printf(" users:(%s)", ctx_buf);
+				sock_users_fmt(ctx_buf);
 				free(ctx_buf);
 			}
 		}
-		printf("\n");
+		if (!json_output)
+			printf("\n");
 	}
 }
 
@@ -2291,7 +2312,9 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
 	char name[128];
 	struct sockstat stat = { .name = "*", .peer_name = "*" };
 
-	parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
+	json_print_opening();
+
+	parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr *)(r + 1),
 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
 	stat.type  = r->udiag_type;
@@ -2324,21 +2347,28 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
 		return 0;
 
 	unix_stats_print(&stat, f);
-
-	if (show_mem) {
-		printf("\t");
+if (show_mem) {
+		if (!json_output)
+			printf("\t");
 		print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
 	}
 	if (show_details) {
 		if (tb[UNIX_DIAG_SHUTDOWN]) {
 			unsigned char mask;
 			mask = *(__u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
-			printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+			sock_conn_fmt(mask);
 		}
 	}
-	if (show_mem || show_details)
-		printf("\n");
+		if (show_mem || show_details)
+		if (!json_output)
+			printf("\n");
 
+	if (json_output) {
+		printf("}\n");
+	}
+
+	if (name)
+		free(name);
 	return 0;
 }
 
@@ -2480,7 +2510,8 @@ static int packet_stats_print(struct sockstat *s, const struct filter *f)
 			return 1;
 	}
 
-	sock_state_print(s, s->type == SOCK_RAW ? "p_raw" : "p_dgr");
+	sock_state_fmt(s, sstate_name, s->type == SOCK_RAW ? "p_raw" : "p_dgr",
+		       	netid_width, state_width);
 
 	if (s->prot == 3)
 		addr = "*";
@@ -2492,25 +2523,35 @@ static int packet_stats_print(struct sockstat *s, const struct filter *f)
 	else
 		port = xll_index_to_name(s->iface);
 
-	sock_addr_print(addr, ":", port, NULL);
-	sock_addr_print("", "*", "", NULL);
+	if (json_output)
+		printf("\t,\"peers\": {\n");
+
+	sock_addr_fmt(addr, addr_width, ":",
+			serv_width, port,
+			NULL, "local");
+	sock_addr_fmt("", addr_width, "*",
+			serv_width, "",
+			NULL, "remote");
+
+	if (json_output)
+		printf("}\n");
 
 	if (show_proc_ctx || show_sock_ctx) {
 		if (find_entry(s->ino, &buf,
-					(show_proc_ctx & show_sock_ctx) ?
-					PROC_SOCK_CTX : PROC_CTX) > 0) {
-			printf(" users:(%s)", buf);
+			       (show_proc_ctx & show_sock_ctx) ?
+			       PROC_SOCK_CTX : PROC_CTX) > 0) {
+			sock_users_fmt(buf);
 			free(buf);
 		}
 	} else if (show_users) {
 		if (find_entry(s->ino, &buf, USERS) > 0) {
-			printf(" users:(%s)", buf);
+			sock_users_fmt(buf);
 			free(buf);
 		}
 	}
 
 	if (show_details)
-		sock_details_print(s);
+		sock_details_fmt(s, GENERIC_DETAIL, 0, 0);
 
 	return 0;
 }
@@ -2527,7 +2568,9 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
 	uint32_t fanout = 0;
 	bool has_fanout = false;
 
-	parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
+	json_print_opening();
+
+	parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(r + 1),
 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
 	/* use /proc/net/packet if all info are not available */
@@ -2567,60 +2610,9 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
 	if (packet_stats_print(&stat, f))
 		return 0;
 
-	if (show_details) {
-		if (pinfo) {
-			printf("\n\tver:%d", pinfo->pdi_version);
-			printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
-			printf(" flags( ");
-			if (pinfo->pdi_flags & PDI_RUNNING)
-				printf("running");
-			if (pinfo->pdi_flags & PDI_AUXDATA)
-				printf(" auxdata");
-			if (pinfo->pdi_flags & PDI_ORIGDEV)
-				printf(" origdev");
-			if (pinfo->pdi_flags & PDI_VNETHDR)
-				printf(" vnethdr");
-			if (pinfo->pdi_flags & PDI_LOSS)
-				printf(" loss");
-			if (!pinfo->pdi_flags)
-				printf("0");
-			printf(" )");
-		}
-		if (ring_rx) {
-			printf("\n\tring_rx(");
-			packet_show_ring(ring_rx);
-			printf(")");
-		}
-		if (ring_tx) {
-			printf("\n\tring_tx(");
-			packet_show_ring(ring_tx);
-			printf(")");
-		}
-		if (has_fanout) {
-			uint16_t type = (fanout >> 16) & 0xffff;
-
-			printf("\n\tfanout(");
-			printf("id:%d,", fanout & 0xffff);
-			printf("type:");
-
-			if (type == 0)
-				printf("hash");
-			else if (type == 1)
-				printf("lb");
-			else if (type == 2)
-				printf("cpu");
-			else if (type == 3)
-				printf("roll");
-			else if (type == 4)
-				printf("random");
-			else if (type == 5)
-				printf("qm");
-			else
-				printf("0x%x", type);
-
-			printf(")");
-		}
-	}
+	if (show_details)
+		packet_details_fmt(pinfo,
+				ring_rx, ring_tx, fanout, has_fanout);
 
 	if (show_bpf && tb[PACKET_DIAG_FILTER]) {
 		struct sock_filter *fil =
@@ -2628,15 +2620,15 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
 		int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
 			  sizeof(struct sock_filter);
 
-		printf("\n\tbpf filter (%d): ", num);
-		while (num) {
-			printf(" 0x%02x %u %u %u,",
-			      fil->code, fil->jt, fil->jf, fil->k);
-			num--;
-			fil++;
-		}
+		bpf_filter_fmt(fil, num);
 	}
-	printf("\n");
+
+	if (json_output)
+		printf("}\n");
+	else
+		printf("\n");
+
+
 	return 0;
 }
 
@@ -2712,6 +2704,7 @@ static int netlink_show_one(struct filter *f,
 	SPRINT_BUF(prot_buf) = {};
 	const char *prot_name;
 	char procname[64] = {};
+	char *rem = "remote";
 
 	st.state = SS_CLOSE;
 	st.rq	 = rq;
@@ -2727,7 +2720,7 @@ static int netlink_show_one(struct filter *f,
 			return 1;
 	}
 
-	sock_state_print(&st, "nl");
+	sock_state_fmt(&st, sstate_name,"nl", netid_width, state_width);
 
 	if (resolve_services)
 		prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
@@ -2759,17 +2752,24 @@ static int netlink_show_one(struct filter *f,
 		int_to_str(pid, procname);
 	}
 
-	sock_addr_print(prot_name, ":", procname, NULL);
+	if (json_output)
+		printf("\t,\"peers\": {\n");
+
+	sock_addr_fmt(prot_name, addr_width, ":", serv_width,
+			procname, NULL, "local");
 
 	if (state == NETLINK_CONNECTED) {
 		char dst_group_buf[30];
 		char dst_pid_buf[30];
-		sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
-				int_to_str(dst_pid, dst_pid_buf), NULL);
+		sock_addr_fmt(int_to_str(dst_group, dst_group_buf), addr_width, ":",
+				serv_width, int_to_str(dst_pid, dst_pid_buf), NULL, rem);
 	} else {
-		sock_addr_print("", "*", "", NULL);
+		sock_addr_fmt("", addr_width, "*", serv_width, "", NULL, rem);
 	}
 
+	if (json_output)
+		printf("}\n");
+
 	char *pid_context = NULL;
 	if (show_proc_ctx) {
 		/* The pid value will either be:
@@ -2783,16 +2783,11 @@ static int netlink_show_one(struct filter *f,
 		else if (pid > 0)
 			getpidcon(pid, &pid_context);
 
-		if (pid_context != NULL) {
-			printf("proc_ctx=%-*s ", serv_width, pid_context);
-			free(pid_context);
-		} else {
-			printf("proc_ctx=%-*s ", serv_width, "unavailable");
-		}
+		proc_fmt(serv_width, pid_context);
 	}
 
 	if (show_details) {
-		printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
+		sock_details_fmt(&st, NETLINK_DETAIL, groups, cb);
 	}
 	printf("\n");
 
@@ -2808,7 +2803,9 @@ static int netlink_show_sock(const struct sockaddr_nl *addr,
 	int rq = 0, wq = 0;
 	unsigned long groups = 0;
 
-	parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr*)(r+1),
+	json_print_opening();
+
+	parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(r + 1),
 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
 	if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]))
@@ -2834,6 +2831,9 @@ static int netlink_show_sock(const struct sockaddr_nl *addr,
 		printf("\n");
 	}
 
+	if (json_output)
+		printf("}\n");
+
 	return 0;
 }
 
@@ -3028,7 +3028,7 @@ static int get_sockstat(struct ssummary *s)
 	return 0;
 }
 
-static int print_summary(void)
+static int print_summary(bool has_successor)
 {
 	struct ssummary s;
 	struct snmpstat sn;
@@ -3040,32 +3040,7 @@ static int print_summary(void)
 
 	get_slabstat(&slabstat);
 
-	printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
-
-	printf("TCP:   %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
-	       s.tcp_total + slabstat.tcp_syns + s.tcp_tws,
-	       sn.tcp_estab,
-	       s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws),
-	       s.tcp_orphans,
-	       slabstat.tcp_syns,
-	       s.tcp_tws, slabstat.tcp_tws,
-	       slabstat.tcp_ports
-	       );
-
-	printf("\n");
-	printf("Transport Total     IP        IPv6\n");
-	printf("*	  %-9d %-9s %-9s\n", slabstat.socks, "-", "-");
-	printf("RAW	  %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
-	printf("UDP	  %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
-	printf("TCP	  %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
-	printf("INET	  %-9d %-9d %-9d\n",
-	       s.raw4+s.udp4+s.tcp4_hashed+
-	       s.raw6+s.udp6+s.tcp6_hashed,
-	       s.raw4+s.udp4+s.tcp4_hashed,
-	       s.raw6+s.udp6+s.tcp6_hashed);
-	printf("FRAG	  %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6);
-
-	printf("\n");
+	sock_summary_fmt(&s, &sn, &slabstat, has_successor);
 
 	if (json_output && has_successor)
 		printf(",\n");
@@ -3406,11 +3381,10 @@ int main(int argc, char *argv[])
 	argc -= optind;
 	argv += optind;
 
-	if (do_summary) {
-		print_summary();
-		if (do_default && argc == 0)
-			exit(0);
-	}
+	if (json_output)
+		printf("{\n");
+
+
 
 	/* Now parse filter... */
 	if (argc == 0 && filter_fp) {
-- 
1.9.1

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

* [PATCH 07/10] ss: renaming and export of current_filter
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (5 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 06/10] ss: replaced old output mechanisms with fmt handlers interfaces Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 08/10] ss: symmetrical subhandler output extension example Matthias Tafelmeier
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

Exported current_filter as ss_current_filter, because in
the fmt handlers, I need that piece of info to resolve out issues of json.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 218 +++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 109 insertions(+), 109 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index a760cf9..24f08d0 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -199,7 +199,7 @@ static const struct filter default_afs[AF_MAX] = {
 };
 
 static int do_default = 1;
-static struct filter current_filter;
+struct filter ss_current_filter;
 
 static void filter_db_set(struct filter *f, int db)
 {
@@ -1189,7 +1189,7 @@ void *parse_hostcond(char *addr, bool is_port)
 	struct aafilter a = { .port = -1 };
 	struct aafilter *res;
 	int fam = preferred_family;
-	struct filter *f = &current_filter;
+	struct filter *f = &ss_current_filter;
 
 	if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
 		char *p;
@@ -1288,9 +1288,9 @@ void *parse_hostcond(char *addr, bool is_port)
 			if (get_integer(&a.port, port, 0)) {
 				struct servent *se1 = NULL;
 				struct servent *se2 = NULL;
-				if (current_filter.dbs&(1<<UDP_DB))
+				if (ss_current_filter.dbs & (1 << UDP_DB))
 					se1 = getservbyname(port, UDP_PROTO);
-				if (current_filter.dbs&(1<<TCP_DB))
+				if (ss_current_filter.dbs & (1 << TCP_DB))
 					se2 = getservbyname(port, TCP_PROTO);
 				if (se1 && se2 && se1->s_port != se2->s_port) {
 					fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
@@ -1304,9 +1304,9 @@ void *parse_hostcond(char *addr, bool is_port)
 					struct scache *s;
 					for (s = rlist; s; s = s->next) {
 						if ((s->proto == UDP_PROTO &&
-						     (current_filter.dbs&(1<<UDP_DB))) ||
+						     (ss_current_filter.dbs&(1<<UDP_DB))) ||
 						    (s->proto == TCP_PROTO &&
-						     (current_filter.dbs&(1<<TCP_DB)))) {
+						     (ss_current_filter.dbs&(1<<TCP_DB)))) {
 							if (s->name && strcmp(s->name, port) == 0) {
 								if (a.port > 0 && a.port != s->port) {
 									fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
@@ -3221,19 +3221,19 @@ int main(int argc, char *argv[])
 			follow_events = 1;
 			break;
 		case 'd':
-			filter_db_set(&current_filter, DCCP_DB);
+			filter_db_set(&ss_current_filter, DCCP_DB);
 			break;
 		case 't':
-			filter_db_set(&current_filter, TCP_DB);
+			filter_db_set(&ss_current_filter, TCP_DB);
 			break;
 		case 'u':
-			filter_db_set(&current_filter, UDP_DB);
+			filter_db_set(&ss_current_filter, UDP_DB);
 			break;
 		case 'w':
-			filter_db_set(&current_filter, RAW_DB);
+			filter_db_set(&ss_current_filter, RAW_DB);
 			break;
 		case 'x':
-			filter_af_set(&current_filter, AF_UNIX);
+			filter_af_set(&ss_current_filter, AF_UNIX);
 			break;
 		case 'a':
 			state_filter = SS_ALL;
@@ -3242,25 +3242,25 @@ int main(int argc, char *argv[])
 			state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE);
 			break;
 		case '4':
-			filter_af_set(&current_filter, AF_INET);
+			filter_af_set(&ss_current_filter, AF_INET);
 			break;
 		case '6':
-			filter_af_set(&current_filter, AF_INET6);
+			filter_af_set(&ss_current_filter, AF_INET6);
 			break;
 		case '0':
-			filter_af_set(&current_filter, AF_PACKET);
+			filter_af_set(&ss_current_filter, AF_PACKET);
 			break;
 		case 'f':
 			if (strcmp(optarg, "inet") == 0)
-				filter_af_set(&current_filter, AF_INET);
+				filter_af_set(&ss_current_filter, AF_INET);
 			else if (strcmp(optarg, "inet6") == 0)
-				filter_af_set(&current_filter, AF_INET6);
+				filter_af_set(&ss_current_filter, AF_INET6);
 			else if (strcmp(optarg, "link") == 0)
-				filter_af_set(&current_filter, AF_PACKET);
+				filter_af_set(&ss_current_filter, AF_PACKET);
 			else if (strcmp(optarg, "unix") == 0)
-				filter_af_set(&current_filter, AF_UNIX);
+				filter_af_set(&ss_current_filter, AF_UNIX);
 			else if (strcmp(optarg, "netlink") == 0)
-				filter_af_set(&current_filter, AF_NETLINK);
+				filter_af_set(&ss_current_filter, AF_NETLINK);
 			else if (strcmp(optarg, "help") == 0)
 				help();
 			else {
@@ -3273,7 +3273,7 @@ int main(int argc, char *argv[])
 		{
 			char *p, *p1;
 			if (!saw_query) {
-				current_filter.dbs = 0;
+				ss_current_filter.dbs = 0;
 				saw_query = 1;
 				do_default = 0;
 			}
@@ -3282,44 +3282,44 @@ int main(int argc, char *argv[])
 				if ((p1 = strchr(p, ',')) != NULL)
 					*p1 = 0;
 				if (strcmp(p, "all") == 0) {
-					filter_default_dbs(&current_filter);
+					filter_default_dbs(&ss_current_filter);
 				} else if (strcmp(p, "inet") == 0) {
-					filter_db_set(&current_filter, UDP_DB);
-					filter_db_set(&current_filter, DCCP_DB);
-					filter_db_set(&current_filter, TCP_DB);
-					filter_db_set(&current_filter, RAW_DB);
+					filter_db_set(&ss_current_filter, UDP_DB);
+					filter_db_set(&ss_current_filter, DCCP_DB);
+					filter_db_set(&ss_current_filter, TCP_DB);
+					filter_db_set(&ss_current_filter, RAW_DB);
 				} else if (strcmp(p, "udp") == 0) {
-					filter_db_set(&current_filter, UDP_DB);
+					filter_db_set(&ss_current_filter, UDP_DB);
 				} else if (strcmp(p, "dccp") == 0) {
-					filter_db_set(&current_filter, DCCP_DB);
+					filter_db_set(&ss_current_filter, DCCP_DB);
 				} else if (strcmp(p, "tcp") == 0) {
-					filter_db_set(&current_filter, TCP_DB);
+					filter_db_set(&ss_current_filter, TCP_DB);
 				} else if (strcmp(p, "raw") == 0) {
-					filter_db_set(&current_filter, RAW_DB);
+					filter_db_set(&ss_current_filter, RAW_DB);
 				} else if (strcmp(p, "unix") == 0) {
-					filter_db_set(&current_filter, UNIX_ST_DB);
-					filter_db_set(&current_filter, UNIX_DG_DB);
-					filter_db_set(&current_filter, UNIX_SQ_DB);
+					filter_db_set(&ss_current_filter, UNIX_ST_DB);
+					filter_db_set(&ss_current_filter, UNIX_DG_DB);
+					filter_db_set(&ss_current_filter, UNIX_SQ_DB);
 				} else if (strcasecmp(p, "unix_stream") == 0 ||
 					   strcmp(p, "u_str") == 0) {
-					filter_db_set(&current_filter, UNIX_ST_DB);
+					filter_db_set(&ss_current_filter, UNIX_ST_DB);
 				} else if (strcasecmp(p, "unix_dgram") == 0 ||
 					   strcmp(p, "u_dgr") == 0) {
-					filter_db_set(&current_filter, UNIX_DG_DB);
+					filter_db_set(&ss_current_filter, UNIX_DG_DB);
 				} else if (strcasecmp(p, "unix_seqpacket") == 0 ||
 					   strcmp(p, "u_seq") == 0) {
-					filter_db_set(&current_filter, UNIX_SQ_DB);
+					filter_db_set(&ss_current_filter, UNIX_SQ_DB);
 				} else if (strcmp(p, "packet") == 0) {
-					filter_db_set(&current_filter, PACKET_R_DB);
-					filter_db_set(&current_filter, PACKET_DG_DB);
+					filter_db_set(&ss_current_filter, PACKET_R_DB);
+					filter_db_set(&ss_current_filter, PACKET_DG_DB);
 				} else if (strcmp(p, "packet_raw") == 0 ||
 					   strcmp(p, "p_raw") == 0) {
-					filter_db_set(&current_filter, PACKET_R_DB);
+					filter_db_set(&ss_current_filter, PACKET_R_DB);
 				} else if (strcmp(p, "packet_dgram") == 0 ||
 					   strcmp(p, "p_dgr") == 0) {
-					filter_db_set(&current_filter, PACKET_DG_DB);
+					filter_db_set(&ss_current_filter, PACKET_DG_DB);
 				} else if (strcmp(p, "netlink") == 0) {
-					filter_db_set(&current_filter, NETLINK_DB);
+					filter_db_set(&ss_current_filter, NETLINK_DB);
 				} else {
 					fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
 					usage();
@@ -3388,7 +3388,7 @@ int main(int argc, char *argv[])
 
 	/* Now parse filter... */
 	if (argc == 0 && filter_fp) {
-		if (ssfilter_parse(&current_filter.f, 0, NULL, filter_fp))
+		if (ssfilter_parse(&ss_current_filter.f, 0, NULL, filter_fp))
 			usage();
 	}
 
@@ -3414,32 +3414,32 @@ int main(int argc, char *argv[])
 
 	if (do_default) {
 		state_filter = state_filter ? state_filter : SS_CONN;
-		filter_default_dbs(&current_filter);
+		filter_default_dbs(&ss_current_filter);
 	}
 
-	filter_states_set(&current_filter, state_filter);
-	filter_merge_defaults(&current_filter);
+	filter_states_set(&ss_current_filter, state_filter);
+	filter_merge_defaults(&ss_current_filter);
 
 	if (resolve_services && resolve_hosts &&
-	    (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
+	    (ss_current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
 		init_service_resolver();
 
-	if (current_filter.dbs == 0) {
+	if (ss_current_filter.dbs == 0) {
 		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
 		exit(0);
 	}
-	if (current_filter.families == 0) {
+	if (ss_current_filter.families == 0) {
 		fprintf(stderr, "ss: no families to show with such filter.\n");
 		exit(0);
 	}
-	if (current_filter.states == 0) {
+	if (ss_current_filter.states == 0) {
 		fprintf(stderr, "ss: no socket states to show with such filter.\n");
 		exit(0);
 	}
 
 	if (dump_tcpdiag) {
 		FILE *dump_fp = stdout;
-		if (!(current_filter.dbs & (1<<TCP_DB))) {
+		if (!(ss_current_filter.dbs & (1<<TCP_DB))) {
 			fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n");
 			exit(0);
 		}
@@ -3451,25 +3451,25 @@ int main(int argc, char *argv[])
 			}
 		}
 		printf("\"TCP\": [\n");
-		inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
-		res_json_fmt_branch(current_filter.dbs & (1<<NETLINK_DB) ||
-				current_filter.dbs & PACKET_DBM ||
-				current_filter.dbs & UNIX_DBM ||
-				current_filter.dbs & (1<<RAW_DB) ||
-				current_filter.dbs & (1<<UDP_DB) ||
-				current_filter.dbs & (1<<TCP_DB) ||
-				current_filter.dbs & (1<<DCCP_DB), ']');
+		inet_show_netlink(&ss_current_filter, dump_fp, IPPROTO_TCP);
+		res_json_fmt_branch(ss_current_filter.dbs & (1<<NETLINK_DB) ||
+				ss_current_filter.dbs & PACKET_DBM ||
+				ss_current_filter.dbs & UNIX_DBM ||
+				ss_current_filter.dbs & (1<<RAW_DB) ||
+				ss_current_filter.dbs & (1<<UDP_DB) ||
+				ss_current_filter.dbs & (1<<TCP_DB) ||
+				ss_current_filter.dbs & (1<<DCCP_DB), ']');
 		fflush(dump_fp);
 		exit(0);
 	}
 
 	if (do_summary) {
-		print_summary(current_filter.dbs & PACKET_DBM ||
-				current_filter.dbs & UNIX_DBM ||
-				current_filter.dbs & (1<<RAW_DB) ||
-				current_filter.dbs & (1<<UDP_DB) ||
-				current_filter.dbs & (1<<TCP_DB) ||
-				current_filter.dbs & (1<<DCCP_DB));
+		print_summary(ss_current_filter.dbs & PACKET_DBM ||
+				ss_current_filter.dbs & UNIX_DBM ||
+				ss_current_filter.dbs & (1<<RAW_DB) ||
+				ss_current_filter.dbs & (1<<UDP_DB) ||
+				ss_current_filter.dbs & (1<<TCP_DB) ||
+				ss_current_filter.dbs & (1<<DCCP_DB));
 		if (do_default && argc == 0) {
 			if (json_output) {
 				printf("}\n");
@@ -3478,15 +3478,15 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
+	if (ssfilter_parse(&ss_current_filter.f, argc, argv, filter_fp))
 		usage();
 
 	netid_width = 0;
-	if (current_filter.dbs&(current_filter.dbs-1))
+	if (ss_current_filter.dbs & (ss_current_filter.dbs - 1))
 		netid_width = 5;
 
 	state_width = 0;
-	if (current_filter.states&(current_filter.states-1))
+	if (ss_current_filter.states & (ss_current_filter.states - 1))
 		state_width = 10;
 
 	screen_width = 80;
@@ -3539,90 +3539,90 @@ int main(int argc, char *argv[])
 
 	fflush(stdout);
 
-	if (current_filter.dbs & (1<<NETLINK_DB)) {
+	if (ss_current_filter.dbs & (1<<NETLINK_DB)) {
 		if (json_output) {
 			printf("\"NETLINK\": [\n");
-			netlink_show(&current_filter);
+			netlink_show(&ss_current_filter);
 			json_first_elem = 1;
-			res_json_fmt_branch(current_filter.dbs & PACKET_DBM ||
-					current_filter.dbs & UNIX_DBM ||
-					current_filter.dbs & (1<<RAW_DB) ||
-					current_filter.dbs & (1<<UDP_DB) ||
-					current_filter.dbs & (1<<TCP_DB) ||
-					current_filter.dbs & (1<<DCCP_DB), ']');
+			res_json_fmt_branch(ss_current_filter.dbs & PACKET_DBM ||
+					ss_current_filter.dbs & UNIX_DBM ||
+					ss_current_filter.dbs & (1<<RAW_DB) ||
+					ss_current_filter.dbs & (1<<UDP_DB) ||
+					ss_current_filter.dbs & (1<<TCP_DB) ||
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 		} else
-			netlink_show(&current_filter);
+			netlink_show(&ss_current_filter);
 	}
-	if (current_filter.dbs & PACKET_DBM) {
+	if (ss_current_filter.dbs & PACKET_DBM) {
 		if (json_output) {
 			printf("\"PACKET\": [\n");
-			packet_show(&current_filter);
+			packet_show(&ss_current_filter);
 			json_first_elem = 1;
 			res_json_fmt_branch(
-					current_filter.dbs & UNIX_DBM ||
-					current_filter.dbs & (1<<RAW_DB) ||
-					current_filter.dbs & (1<<UDP_DB) ||
-					current_filter.dbs & (1<<TCP_DB) ||
-					current_filter.dbs & (1<<DCCP_DB), ']');
+					ss_current_filter.dbs & UNIX_DBM ||
+					ss_current_filter.dbs & (1<<RAW_DB) ||
+					ss_current_filter.dbs & (1<<UDP_DB) ||
+					ss_current_filter.dbs & (1<<TCP_DB) ||
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 		} else
-			packet_show(&current_filter);
+			packet_show(&ss_current_filter);
 	}
-	if (current_filter.dbs & UNIX_DBM) {
+	if (ss_current_filter.dbs & UNIX_DBM) {
 		if (json_output) {
 			printf("\"UNIX\": [\n");
-			unix_show(&current_filter);
+			unix_show(&ss_current_filter);
 			json_first_elem = 1;
 			res_json_fmt_branch(
-					current_filter.dbs & (1<<RAW_DB) ||
-					current_filter.dbs & (1<<UDP_DB) ||
-					current_filter.dbs & (1<<TCP_DB) ||
-					current_filter.dbs & (1<<DCCP_DB), ']');
+					ss_current_filter.dbs & (1<<RAW_DB) ||
+					ss_current_filter.dbs & (1<<UDP_DB) ||
+					ss_current_filter.dbs & (1<<TCP_DB) ||
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 
 		} else
-			unix_show(&current_filter);
+			unix_show(&ss_current_filter);
 	}
-	if (current_filter.dbs & (1<<RAW_DB)) {
+	if (ss_current_filter.dbs & (1<<RAW_DB)) {
 		if (json_output) {
 			printf("\"RAW\": [\n");
-			raw_show(&current_filter);
+			raw_show(&ss_current_filter);
 			json_first_elem = 1;
 			res_json_fmt_branch(
-					current_filter.dbs & (1<<UDP_DB) ||
-					current_filter.dbs & (1<<TCP_DB) ||
-					current_filter.dbs & (1<<DCCP_DB), ']');
+					ss_current_filter.dbs & (1<<UDP_DB) ||
+					ss_current_filter.dbs & (1<<TCP_DB) ||
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 
 		} else
-			raw_show(&current_filter);
+			raw_show(&ss_current_filter);
 	}
-	if (current_filter.dbs & (1<<UDP_DB)) {
+	if (ss_current_filter.dbs & (1<<UDP_DB)) {
 		if (json_output) {
 			printf("\"UDP\": [\n");
-			udp_show(&current_filter);
+			udp_show(&ss_current_filter);
 			json_first_elem = 1;
 			res_json_fmt_branch(
-					current_filter.dbs & (1<<TCP_DB) ||
-					current_filter.dbs & (1<<DCCP_DB), ']');
+					ss_current_filter.dbs & (1<<TCP_DB) ||
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 
 		} else
-			udp_show(&current_filter);
+			udp_show(&ss_current_filter);
 	}
-	if (current_filter.dbs & (1<<TCP_DB)) {
+	if (ss_current_filter.dbs & (1<<TCP_DB)) {
 		if (json_output) {
 			printf("\"TCP\": [\n");
-			tcp_show(&current_filter, IPPROTO_TCP);
+			tcp_show(&ss_current_filter, IPPROTO_TCP);
 			json_first_elem = 1;
 			res_json_fmt_branch(
-					current_filter.dbs & (1<<DCCP_DB), ']');
+					ss_current_filter.dbs & (1<<DCCP_DB), ']');
 		} else
-			tcp_show(&current_filter, IPPROTO_TCP);
+			tcp_show(&ss_current_filter, IPPROTO_TCP);
 	}
-	if (current_filter.dbs & (1<<DCCP_DB)) {
+	if (ss_current_filter.dbs & (1<<DCCP_DB)) {
 		if (json_output) {
 			printf("\"DCCP\": [\n");
-			tcp_show(&current_filter, IPPROTO_DCCP);
+			tcp_show(&ss_current_filter, IPPROTO_DCCP);
 			printf("]\n");
 		} else
-			tcp_show(&current_filter, IPPROTO_DCCP);
+			tcp_show(&ss_current_filter, IPPROTO_DCCP);
 	}
 
 	if (json_output) {
@@ -3632,7 +3632,7 @@ int main(int argc, char *argv[])
 	fflush(stdout);
 
 	if (follow_events)
-		exit(handle_follow_request(&current_filter));
+		exit(handle_follow_request(&ss_current_filter));
 
 	if (show_users || show_proc_ctx || show_sock_ctx)
 		user_ent_destroy();
-- 
1.9.1

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

* [PATCH 08/10] ss: symmetrical subhandler output extension example
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (6 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 07/10] ss: renaming and export of current_filter Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-10 12:19   ` Sergei Shtylyov
  2015-08-09 23:13 ` [PATCH 09/10] ss: symmetrical formatter " Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 10/10] ss: fixed free on local array for valid json output Matthias Tafelmeier
  9 siblings, 1 reply; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

This small sized patch shall convey the locations which have to be
changed for a symmetrical output extension. Symmetrical means in this
context all existing semantically related handlers in the diverse
formatters (for hr and json up to now).

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss_hr_fmt.c   | 2 ++
 misc/ss_json_fmt.c | 4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/misc/ss_hr_fmt.c b/misc/ss_hr_fmt.c
index 6955ea5..40b6b7c 100644
--- a/misc/ss_hr_fmt.c
+++ b/misc/ss_hr_fmt.c
@@ -82,6 +82,8 @@ static void tcp_stats_hr_fmt(struct tcpstat *s)
 		printf(" reordering:%d", s->reordering);
 	if (s->rcv_rtt)
 		printf(" rcv_rtt:%g", s->rcv_rtt);
+	if (s->rcv_space)
+		printf(" rcv_space:%d", s->rcv_space);
 
 	CHECK_FMT_ADAPT(s->rcv_space, s,
 	hr_handler_must_be_adapted_accordingly_when_json_fmt_is_extended);
diff --git a/misc/ss_json_fmt.c b/misc/ss_json_fmt.c
index f1a53cd..e80f063 100644
--- a/misc/ss_json_fmt.c
+++ b/misc/ss_json_fmt.c
@@ -161,7 +161,9 @@ static void tcp_stats_json_fmt(struct tcpstat *s)
 	if (s->rcv_rtt) {
 		printf(",\n%s\"rcv_rtt\": %g", indent1, s->rcv_rtt);
 	}
-
+	if (s->rcv_space) {
+		printf(",\n%s\"rcv_space\": %d", indent1, s->rcv_space);
+	}
 	/*deal with special case */
 	res_json_fmt_branch(s->ss.state == SS_LISTEN, ' ');
 
-- 
1.9.1

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

* [PATCH 09/10] ss: symmetrical formatter extension example
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (7 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 08/10] ss: symmetrical subhandler output extension example Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  2015-08-09 23:13 ` [PATCH 10/10] ss: fixed free on local array for valid json output Matthias Tafelmeier
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

This commit shall show shortly where to place changes when one wants to
extend an ss output formatter with a new handler (format print
procedure). The extension is done symmetrically. That means, every up to
now existing formatter is extended with a semantically equivalent
handler (hr and json formatter).

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss_hr_fmt.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_json_fmt.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_out_fmt.c  | 10 +++++++++
 misc/ss_out_fmt.h  | 10 +++++++++
 4 files changed, 146 insertions(+)

diff --git a/misc/ss_hr_fmt.c b/misc/ss_hr_fmt.c
index 40b6b7c..ca73dda 100644
--- a/misc/ss_hr_fmt.c
+++ b/misc/ss_hr_fmt.c
@@ -242,6 +242,66 @@ static void packet_show_ring_hr_fmt(struct packet_diag_ring *ring)
 	printf(",features:0x%x", ring->pdr_features);
 }
 
+static void packet_details_hr_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	if (pinfo) {
+		printf("\n\tver:%d", pinfo->pdi_version);
+		printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
+		printf(" flags( ");
+		if (pinfo->pdi_flags & PDI_RUNNING)
+			printf("running");
+		if (pinfo->pdi_flags & PDI_AUXDATA)
+			printf(" auxdata");
+		if (pinfo->pdi_flags & PDI_ORIGDEV)
+			printf(" origdev");
+		if (pinfo->pdi_flags & PDI_VNETHDR)
+			printf(" vnethdr");
+		if (pinfo->pdi_flags & PDI_LOSS)
+			printf(" loss");
+		if (!pinfo->pdi_flags)
+			printf("0");
+		printf(" )");
+	}
+	if (ring_rx) {
+		printf("\n\tring_rx(");
+		packet_show_ring_fmt(ring_rx);
+		printf(")");
+	}
+	if (ring_tx) {
+		printf("\n\tring_tx(");
+		packet_show_ring_fmt(ring_tx);
+		printf(")");
+	}
+	if (has_fanout) {
+		uint16_t type = (fanout >> 16) & 0xffff;
+
+		printf("\n\tfanout(");
+		printf("id:%d,", fanout & 0xffff);
+		printf("type:");
+
+		if (type == 0)
+			printf("hash");
+		else if (type == 1)
+			printf("lb");
+		else if (type == 2)
+			printf("cpu");
+		else if (type == 3)
+			printf("roll");
+		else if (type == 4)
+			printf("random");
+		else if (type == 5)
+			printf("qm");
+		else
+			printf("0x%x", type);
+
+		printf(")");
+	}
+}
+
 const struct fmt_op_hub hr_output_op = {
 	.tcp_stats_fmt = tcp_stats_hr_fmt,
 	.tcp_timer_fmt = tcp_timer_hr_fmt,
@@ -257,4 +317,5 @@ const struct fmt_op_hub hr_output_op = {
 	.opt_fmt = opt_hr_fmt,
 	.proc_fmt = proc_hr_fmt,
 	.packet_show_ring_fmt = packet_show_ring_hr_fmt,
+	.packet_details_fmt = packet_details_hr_fmt
 };
diff --git a/misc/ss_json_fmt.c b/misc/ss_json_fmt.c
index e80f063..e7a1270 100644
--- a/misc/ss_json_fmt.c
+++ b/misc/ss_json_fmt.c
@@ -383,6 +383,70 @@ static void packet_show_ring_json_fmt(struct packet_diag_ring *ring)
 	printf("\"features_0x\" : \"%x\"\n", ring->pdr_features);
 }
 
+static void packet_details_json_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	printf(",\n");
+	if (pinfo) {
+		printf("\t\"ver\": \"%d\",\n", pinfo->pdi_version);
+		printf("\t\"cpy_thresh\": \"%d\",\n", pinfo->pdi_copy_thresh);
+		printf("\t\"flags\": \"");
+		if (pinfo->pdi_flags & PDI_RUNNING)
+			printf("running");
+		if (pinfo->pdi_flags & PDI_AUXDATA)
+			printf("_auxdata");
+		if (pinfo->pdi_flags & PDI_ORIGDEV)
+			printf("_origdev");
+		if (pinfo->pdi_flags & PDI_VNETHDR)
+			printf("_vnethdr");
+		if (pinfo->pdi_flags & PDI_LOSS)
+			printf("_loss");
+		if (!pinfo->pdi_flags)
+			printf("0");
+		printf("\"");
+		res_json_fmt_branch(ring_rx || ring_tx || has_fanout, ' ');
+	}
+	if (ring_rx) {
+		printf("\t\"ring_rx\": {");
+		packet_show_ring_fmt(ring_rx);
+		printf("}");
+		res_json_fmt_branch(ring_tx || has_fanout, ' ');
+	}
+	if (ring_tx) {
+		printf("\t\"ring_tx\": {");
+		packet_show_ring_fmt(ring_tx);
+		printf("}");
+		res_json_fmt_branch(has_fanout, ' ');
+	}
+	if (has_fanout) {
+		uint16_t type = (fanout >> 16) & 0xffff;
+
+		printf("\t\"fanout\": \"");
+		printf("id:%d,", fanout & 0xffff);
+		printf("type:");
+
+		if (type == 0)
+			printf("hash");
+		else if (type == 1)
+			printf("lb");
+		else if (type == 2)
+			printf("cpu");
+		else if (type == 3)
+			printf("roll");
+		else if (type == 4)
+			printf("random");
+		else if (type == 5)
+			printf("qm");
+		else
+			printf("0x%x", type);
+
+		printf("\"");
+	}
+}
+
 const struct fmt_op_hub json_output_op = {
 	.tcp_stats_fmt = tcp_stats_json_fmt,
 	.tcp_timer_fmt = tcp_timer_json_fmt,
@@ -398,4 +462,5 @@ const struct fmt_op_hub json_output_op = {
 	.opt_fmt = opt_json_fmt,
 	.proc_fmt = proc_json_fmt,
 	.packet_show_ring_fmt = packet_show_ring_json_fmt,
+	.packet_details_fmt = packet_details_json_fmt
 };
diff --git a/misc/ss_out_fmt.c b/misc/ss_out_fmt.c
index e17d898..3a0eb12 100644
--- a/misc/ss_out_fmt.c
+++ b/misc/ss_out_fmt.c
@@ -125,3 +125,13 @@ void packet_show_ring_fmt(struct packet_diag_ring *ring)
 {
 	fmt_op_hub[fmt_type]->packet_show_ring_fmt(ring);
 }
+void packet_details_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	fmt_op_hub[fmt_type]->packet_details_fmt(pinfo,
+			ring_rx, ring_tx, fanout, has_fanout);
+}
+
diff --git a/misc/ss_out_fmt.h b/misc/ss_out_fmt.h
index b74f668..9443d44 100644
--- a/misc/ss_out_fmt.h
+++ b/misc/ss_out_fmt.h
@@ -54,6 +54,11 @@ struct fmt_op_hub {
 	void (*opt_fmt)(char *opt);
 	void (*proc_fmt)(int serv_width, char *pid_ctx);
 	void (*packet_show_ring_fmt)(struct packet_diag_ring *ring);
+	void (*packet_details_fmt)(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout);
 };
 
 void tcp_stats_fmt(struct tcpstat *s);
@@ -74,6 +79,11 @@ void bpf_filter_fmt(struct sock_filter *f, int num);
 void opt_fmt(char *opt);
 void proc_fmt(int serv_width, char *pid_ctx);
 void packet_show_ring_fmt(struct packet_diag_ring *ring);
+void packet_details_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout);
 
 /*unisonly utilized formatting parts*/
 char *sprint_bw(char *buf, double bw);
-- 
1.9.1

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

* [PATCH 10/10] ss: fixed free on local array for valid json output
  2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
                   ` (8 preceding siblings ...)
  2015-08-09 23:13 ` [PATCH 09/10] ss: symmetrical formatter " Matthias Tafelmeier
@ 2015-08-09 23:13 ` Matthias Tafelmeier
  9 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-09 23:13 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

Minor fix to enable json output. Freeing of automatic char array name
which will get freed after function stack cleanup. Another one after
tcp_stats_fmt for freeing automatic tcpstats struct instance.

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 24f08d0..dc6e3f1 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1665,10 +1665,6 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
 		s.segs_out = info->tcpi_segs_out;
 		s.segs_in = info->tcpi_segs_in;
 		tcp_stats_fmt(&s);
-		if (s.dctcp)
-			free(s.dctcp);
-		if (s.cong_alg)
-			free(s.cong_alg);
 	}
 }
 
@@ -2367,8 +2363,6 @@ if (show_mem) {
 		printf("}\n");
 	}
 
-	if (name)
-		free(name);
 	return 0;
 }
 
-- 
1.9.1

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

* Re: [PATCH 08/10] ss: symmetrical subhandler output extension example
  2015-08-09 23:13 ` [PATCH 08/10] ss: symmetrical subhandler output extension example Matthias Tafelmeier
@ 2015-08-10 12:19   ` Sergei Shtylyov
  2015-08-10 14:53     ` Eric Dumazet
  0 siblings, 1 reply; 16+ messages in thread
From: Sergei Shtylyov @ 2015-08-10 12:19 UTC (permalink / raw)
  To: Matthias Tafelmeier, netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

On 8/10/2015 2:13 AM, Matthias Tafelmeier wrote:

> This small sized patch shall convey the locations which have to be
> changed for a symmetrical output extension. Symmetrical means in this
> context all existing semantically related handlers in the diverse
> formatters (for hr and json up to now).

> Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
> Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>

[...]

> diff --git a/misc/ss_json_fmt.c b/misc/ss_json_fmt.c
> index f1a53cd..e80f063 100644
> --- a/misc/ss_json_fmt.c
> +++ b/misc/ss_json_fmt.c
> @@ -161,7 +161,9 @@ static void tcp_stats_json_fmt(struct tcpstat *s)
>   	if (s->rcv_rtt) {
>   		printf(",\n%s\"rcv_rtt\": %g", indent1, s->rcv_rtt);
>   	}
> -
> +	if (s->rcv_space) {
> +		printf(",\n%s\"rcv_space\": %d", indent1, s->rcv_space);
> +	}

    {} not needed. I guess you haven't run your patches thru 
scripts/checkpatch.pl?

WBR, Sergei

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

* Re: [PATCH 08/10] ss: symmetrical subhandler output extension example
  2015-08-10 12:19   ` Sergei Shtylyov
@ 2015-08-10 14:53     ` Eric Dumazet
  2015-08-10 17:06       ` Matthias Tafelmeier
  2015-08-10 18:19       ` Sergei Shtylyov
  0 siblings, 2 replies; 16+ messages in thread
From: Eric Dumazet @ 2015-08-10 14:53 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Matthias Tafelmeier, netdev, hagen, shemminger, fw, edumazet, daniel

On Mon, 2015-08-10 at 15:19 +0300, Sergei Shtylyov wrote:

>     {} not needed. I guess you haven't run your patches thru 
> scripts/checkpatch.pl?
> 

Yes, although this is missing from iproute2 sources ;)

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

* Re: [PATCH 08/10] ss: symmetrical subhandler output extension example
  2015-08-10 14:53     ` Eric Dumazet
@ 2015-08-10 17:06       ` Matthias Tafelmeier
  2015-08-10 18:19       ` Sergei Shtylyov
  1 sibling, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-10 17:06 UTC (permalink / raw)
  To: Eric Dumazet, Sergei Shtylyov
  Cc: netdev, hagen, shemminger, fw, edumazet, daniel

[-- Attachment #1: Type: text/plain, Size: 1099 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA384


>> {} not needed. I guess you haven't run your patches thru 
>> scripts/checkpatch.pl?
>> 
> 
> Yes, although this is missing from iproute2 sources ;)
> 
> 

Thank you for reviewing so far.

I see there slipped some parts of the patch through according
checkpatch.pl for which I am responsible. I will give a V2 patch for
these asap.

Nevertheless, there are parts of the patch for which I am not liable,
so please bear with me. I only copied those over from the origin
version. Well, I am quite prepared to correct them as well in order to
come up for the "history break".


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBCQAGBQJVyNoMAAoJEOAWT1uK3zQ7jOcH/3WJWNM+gcKDz/Hbj2oQLcli
M3jkIICJFZhSlCUqI0DjmVecy3ryDtxZjM4HuHcqPP8nqmdP7ykiO7p89PLTF2iC
XgA7UMMTByNJD6WSz7kjwWFlPXhvffrhE4yNZe+WkTE+HrJ8GPVydnhnr+Xo4L3g
YYDns9VWAHQgD14bd36FaoZkYmlXM1WQJZm5sgMCYWEq8ZpIHFJhqKRD6Y7e29rK
eI8BQchv30QHQiCzFOIyTqm7ncUb9CE8brBC1IFEFs9Eli5CQCoiriXANR3ntsjB
dU/6P3NuyAkis7CWILgGaKSNi0h/DPhszZQh5Gfjl4FFE5vszCVup6pM1evBWH0=
=mcKX
-----END PGP SIGNATURE-----

[-- Attachment #2: 0x8ADF343B.asc --]
[-- Type: application/pgp-keys, Size: 3964 bytes --]

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

* Re: [PATCH 08/10] ss: symmetrical subhandler output extension example
  2015-08-10 14:53     ` Eric Dumazet
  2015-08-10 17:06       ` Matthias Tafelmeier
@ 2015-08-10 18:19       ` Sergei Shtylyov
  1 sibling, 0 replies; 16+ messages in thread
From: Sergei Shtylyov @ 2015-08-10 18:19 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Matthias Tafelmeier, netdev, hagen, shemminger, fw, edumazet, daniel

On 08/10/2015 05:53 PM, Eric Dumazet wrote:

>>      {} not needed. I guess you haven't run your patches thru
>> scripts/checkpatch.pl?

> Yes, although this is missing from iproute2 sources ;)

    Oh, sorry, somehow I thought it's a kernel patch. :-)

MBR, Sergei

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

* [PATCH 09/10] ss: symmetrical formatter extension example
  2015-08-10 18:52 V2 iproute2: full ss json support and general output simplification Matthias Tafelmeier
@ 2015-08-10 18:52 ` Matthias Tafelmeier
  0 siblings, 0 replies; 16+ messages in thread
From: Matthias Tafelmeier @ 2015-08-10 18:52 UTC (permalink / raw)
  To: netdev; +Cc: hagen, shemminger, fw, edumazet, daniel

This commit shall show shortly where to place changes when one wants to
extend an ss output formatter with a new handler (format print
procedure). The extension is done symmetrically. That means, every up to
now existing formatter is extended with a semantically equivalent
handler (hr and json formatter).

Signed-off-by: Matthias Tafelmeier <matthias.tafelmeier@gmx.net>
Suggested-by: Hagen Paul Pfeifer <hagen@jauu.net>
---
 misc/ss_hr_fmt.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_json_fmt.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_out_fmt.c  | 10 +++++++++
 misc/ss_out_fmt.h  | 10 +++++++++
 4 files changed, 146 insertions(+)

diff --git a/misc/ss_hr_fmt.c b/misc/ss_hr_fmt.c
index 40b6b7c..ca73dda 100644
--- a/misc/ss_hr_fmt.c
+++ b/misc/ss_hr_fmt.c
@@ -242,6 +242,66 @@ static void packet_show_ring_hr_fmt(struct packet_diag_ring *ring)
 	printf(",features:0x%x", ring->pdr_features);
 }
 
+static void packet_details_hr_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	if (pinfo) {
+		printf("\n\tver:%d", pinfo->pdi_version);
+		printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
+		printf(" flags( ");
+		if (pinfo->pdi_flags & PDI_RUNNING)
+			printf("running");
+		if (pinfo->pdi_flags & PDI_AUXDATA)
+			printf(" auxdata");
+		if (pinfo->pdi_flags & PDI_ORIGDEV)
+			printf(" origdev");
+		if (pinfo->pdi_flags & PDI_VNETHDR)
+			printf(" vnethdr");
+		if (pinfo->pdi_flags & PDI_LOSS)
+			printf(" loss");
+		if (!pinfo->pdi_flags)
+			printf("0");
+		printf(" )");
+	}
+	if (ring_rx) {
+		printf("\n\tring_rx(");
+		packet_show_ring_fmt(ring_rx);
+		printf(")");
+	}
+	if (ring_tx) {
+		printf("\n\tring_tx(");
+		packet_show_ring_fmt(ring_tx);
+		printf(")");
+	}
+	if (has_fanout) {
+		uint16_t type = (fanout >> 16) & 0xffff;
+
+		printf("\n\tfanout(");
+		printf("id:%d,", fanout & 0xffff);
+		printf("type:");
+
+		if (type == 0)
+			printf("hash");
+		else if (type == 1)
+			printf("lb");
+		else if (type == 2)
+			printf("cpu");
+		else if (type == 3)
+			printf("roll");
+		else if (type == 4)
+			printf("random");
+		else if (type == 5)
+			printf("qm");
+		else
+			printf("0x%x", type);
+
+		printf(")");
+	}
+}
+
 const struct fmt_op_hub hr_output_op = {
 	.tcp_stats_fmt = tcp_stats_hr_fmt,
 	.tcp_timer_fmt = tcp_timer_hr_fmt,
@@ -257,4 +317,5 @@ const struct fmt_op_hub hr_output_op = {
 	.opt_fmt = opt_hr_fmt,
 	.proc_fmt = proc_hr_fmt,
 	.packet_show_ring_fmt = packet_show_ring_hr_fmt,
+	.packet_details_fmt = packet_details_hr_fmt
 };
diff --git a/misc/ss_json_fmt.c b/misc/ss_json_fmt.c
index d7dfce9..3d10220 100644
--- a/misc/ss_json_fmt.c
+++ b/misc/ss_json_fmt.c
@@ -355,6 +355,70 @@ static void packet_show_ring_json_fmt(struct packet_diag_ring *ring)
 	printf("\"features_0x\" : \"%x\"\n", ring->pdr_features);
 }
 
+static void packet_details_json_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	printf(",\n");
+	if (pinfo) {
+		printf("\t\"ver\": \"%d\",\n", pinfo->pdi_version);
+		printf("\t\"cpy_thresh\": \"%d\",\n", pinfo->pdi_copy_thresh);
+		printf("\t\"flags\": \"");
+		if (pinfo->pdi_flags & PDI_RUNNING)
+			printf("running");
+		if (pinfo->pdi_flags & PDI_AUXDATA)
+			printf("_auxdata");
+		if (pinfo->pdi_flags & PDI_ORIGDEV)
+			printf("_origdev");
+		if (pinfo->pdi_flags & PDI_VNETHDR)
+			printf("_vnethdr");
+		if (pinfo->pdi_flags & PDI_LOSS)
+			printf("_loss");
+		if (!pinfo->pdi_flags)
+			printf("0");
+		printf("\"");
+		res_json_fmt_branch(ring_rx || ring_tx || has_fanout, ' ');
+	}
+	if (ring_rx) {
+		printf("\t\"ring_rx\": {");
+		packet_show_ring_fmt(ring_rx);
+		printf("}");
+		res_json_fmt_branch(ring_tx || has_fanout, ' ');
+	}
+	if (ring_tx) {
+		printf("\t\"ring_tx\": {");
+		packet_show_ring_fmt(ring_tx);
+		printf("}");
+		res_json_fmt_branch(has_fanout, ' ');
+	}
+	if (has_fanout) {
+		uint16_t type = (fanout >> 16) & 0xffff;
+
+		printf("\t\"fanout\": \"");
+		printf("id:%d,", fanout & 0xffff);
+		printf("type:");
+
+		if (type == 0)
+			printf("hash");
+		else if (type == 1)
+			printf("lb");
+		else if (type == 2)
+			printf("cpu");
+		else if (type == 3)
+			printf("roll");
+		else if (type == 4)
+			printf("random");
+		else if (type == 5)
+			printf("qm");
+		else
+			printf("0x%x", type);
+
+		printf("\"");
+	}
+}
+
 const struct fmt_op_hub json_output_op = {
 	.tcp_stats_fmt = tcp_stats_json_fmt,
 	.tcp_timer_fmt = tcp_timer_json_fmt,
@@ -370,4 +434,5 @@ const struct fmt_op_hub json_output_op = {
 	.opt_fmt = opt_json_fmt,
 	.proc_fmt = proc_json_fmt,
 	.packet_show_ring_fmt = packet_show_ring_json_fmt,
+	.packet_details_fmt = packet_details_json_fmt
 };
diff --git a/misc/ss_out_fmt.c b/misc/ss_out_fmt.c
index e17d898..3a0eb12 100644
--- a/misc/ss_out_fmt.c
+++ b/misc/ss_out_fmt.c
@@ -125,3 +125,13 @@ void packet_show_ring_fmt(struct packet_diag_ring *ring)
 {
 	fmt_op_hub[fmt_type]->packet_show_ring_fmt(ring);
 }
+void packet_details_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout)
+{
+	fmt_op_hub[fmt_type]->packet_details_fmt(pinfo,
+			ring_rx, ring_tx, fanout, has_fanout);
+}
+
diff --git a/misc/ss_out_fmt.h b/misc/ss_out_fmt.h
index b74f668..9443d44 100644
--- a/misc/ss_out_fmt.h
+++ b/misc/ss_out_fmt.h
@@ -54,6 +54,11 @@ struct fmt_op_hub {
 	void (*opt_fmt)(char *opt);
 	void (*proc_fmt)(int serv_width, char *pid_ctx);
 	void (*packet_show_ring_fmt)(struct packet_diag_ring *ring);
+	void (*packet_details_fmt)(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout);
 };
 
 void tcp_stats_fmt(struct tcpstat *s);
@@ -74,6 +79,11 @@ void bpf_filter_fmt(struct sock_filter *f, int num);
 void opt_fmt(char *opt);
 void proc_fmt(int serv_width, char *pid_ctx);
 void packet_show_ring_fmt(struct packet_diag_ring *ring);
+void packet_details_fmt(struct packet_diag_info *pinfo,
+		struct packet_diag_ring *ring_rx,
+		struct packet_diag_ring *ring_tx,
+		uint32_t fanout,
+		bool has_fanout);
 
 /*unisonly utilized formatting parts*/
 char *sprint_bw(char *buf, double bw);
-- 
1.9.1

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

end of thread, other threads:[~2015-08-10 18:52 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-09 23:13 full ss json support and general output simplification Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 02/10] ss: created formatters for json and hr Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 03/10] ss: removed obsolet fmt functions Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 04/10] ss: prepare timer for output handler usage Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 05/10] ss: framed skeleton for json output in ss Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 06/10] ss: replaced old output mechanisms with fmt handlers interfaces Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 07/10] ss: renaming and export of current_filter Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 08/10] ss: symmetrical subhandler output extension example Matthias Tafelmeier
2015-08-10 12:19   ` Sergei Shtylyov
2015-08-10 14:53     ` Eric Dumazet
2015-08-10 17:06       ` Matthias Tafelmeier
2015-08-10 18:19       ` Sergei Shtylyov
2015-08-09 23:13 ` [PATCH 09/10] ss: symmetrical formatter " Matthias Tafelmeier
2015-08-09 23:13 ` [PATCH 10/10] ss: fixed free on local array for valid json output Matthias Tafelmeier
2015-08-10 18:52 V2 iproute2: full ss json support and general output simplification Matthias Tafelmeier
2015-08-10 18:52 ` [PATCH 09/10] ss: symmetrical formatter extension example Matthias Tafelmeier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.