netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3]iproute2: full ss json support and general output simplification
@ 2015-08-20 20:40 Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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          | 1015 ++++++++++++++++++----------------------------------
 misc/ss_hr_fmt.c   |  321 +++++++++++++++++
 misc/ss_hr_fmt.h   |    9 +
 misc/ss_json_fmt.c |  438 +++++++++++++++++++++++
 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, 1566 insertions(+), 658 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] 14+ messages in thread

* [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-23 17:07   ` Stephen Hemminger
  2015-08-20 20:40 ` [PATCH v3 02/10] ss: created formatters for json and hr Matthias Tafelmeier
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 2f34962..83775d1 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];
 
@@ -540,12 +493,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)
 {
@@ -618,17 +565,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[] =
@@ -713,75 +649,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)
@@ -855,13 +722,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)
@@ -1026,13 +886,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)
 {
@@ -2188,11 +2041,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)
 {
@@ -3223,10 +3071,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)
 {
@@ -3281,11 +3125,6 @@ Exit:
 	return ret;
 }
 
-struct snmpstat
-{
-	int tcp_estab;
-};
-
 static int get_snmp_int(char *proto, char *key, int *result)
 {
 	char buf[1024];
@@ -3330,28 +3169,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];
@@ -3818,7 +3635,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..b4dfdc1
--- /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] 14+ messages in thread

* [PATCH v3 02/10] ss: created formatters for json and hr
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 03/10] ss: removed obsolet fmt functions Matthias Tafelmeier
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 | 373 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 misc/ss_json_fmt.h |  24 ++++
 misc/ss_out_fmt.c  | 127 ++++++++++++++++++
 misc/ss_out_fmt.h  |  82 ++++++++++++
 7 files changed, 874 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..d7dfce9
--- /dev/null
+++ b/misc/ss_json_fmt.c
@@ -0,0 +1,373 @@
+#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] 14+ messages in thread

* [PATCH v3 03/10] ss: removed obsolet fmt functions
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 02/10] ss: created formatters for json and hr Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 04/10] ss: prepare timer for output handler usage Matthias Tafelmeier
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 83775d1..4cc6991 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -649,43 +649,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",
@@ -695,33 +658,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)
@@ -1484,122 +1420,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;
@@ -2694,16 +2514,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] 14+ messages in thread

* [PATCH v3 04/10] ss: prepare timer for output handler usage
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (2 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 03/10] ss: removed obsolet fmt functions Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 05/10] ss: framed skeleton for json output in ss Matthias Tafelmeier
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 4cc6991..e7ea041 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -649,7 +649,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] 14+ messages in thread

* [PATCH v3 05/10] ss: framed skeleton for json output in ss
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (3 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 04/10] ss: prepare timer for output handler usage Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 06/10] ss: replaced old output mechanisms with fmt handlers interfaces Matthias Tafelmeier
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 | 198 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 155 insertions(+), 43 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index e7ea041..1bc2546 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;
@@ -716,7 +720,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;
@@ -3069,6 +3072,9 @@ static int print_summary(void)
 
 	printf("\n");
 
+	if (json_output && has_successor)
+		printf(",\n");
+
 	return 0;
 }
 
@@ -3095,6 +3101,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"
@@ -3194,6 +3201,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 }
 
@@ -3209,7 +3217,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':
@@ -3390,6 +3398,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();
@@ -3471,11 +3483,33 @@ 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();
 
@@ -3497,62 +3531,140 @@ 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");
 
-	addrp_width /= 2;
-	addrp_width--;
+		/* Make enough space for the local/remote port field */
+		addr_width -= 13;
+		serv_width += 13;
 
-	serv_width = resolve_services ? 7 : 5;
+		printf("%*s:%-*s %*s:%-*s\n",
+				addr_width, "Local Address", serv_width, "Port",
+				addr_width, "Peer Address", serv_width, "Port");
+	}
 
-	if (addrp_width < 15+serv_width+1)
-		addrp_width = 15+serv_width+1;
+	fflush(stdout);
 
-	addr_width = addrp_width - 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), ']');
 
-	if (netid_width)
-		printf("%-*s ", netid_width, "Netid");
-	if (state_width)
-		printf("%-*s ", state_width, "State");
-	printf("%-6s %-6s ", "Recv-Q", "Send-Q");
+		} 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), ']');
 
-	/* Make enough space for the local/remote port field */
-	addr_width -= 13;
-	serv_width += 13;
+		} 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), ']');
 
-	printf("%*s:%-*s %*s:%-*s\n",
-	       addr_width, "Local Address", serv_width, "Port",
-	       addr_width, "Peer Address", serv_width, "Port");
+		} 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);
+	}
+
+	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] 14+ messages in thread

* [PATCH v3 06/10] ss: replaced old output mechanisms with fmt handlers interfaces
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (4 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 05/10] ss: framed skeleton for json output in ss Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 07/10] ss: renaming and export of current_filter Matthias Tafelmeier
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 | 330 +++++++++++++++++++++++++++++---------------------------------
 1 file changed, 152 insertions(+), 178 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 1bc2546..2fbdd7f 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;
@@ -793,7 +806,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;
@@ -821,8 +835,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,
@@ -1354,21 +1368,27 @@ 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);
 		}
 	}
@@ -1472,16 +1492,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;
@@ -1525,31 +1545,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))
@@ -1662,8 +1665,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);
 	}
 }
 
@@ -1687,6 +1693,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 {
@@ -1710,29 +1718,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;
 }
 
@@ -2083,7 +2091,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;
@@ -2260,27 +2271,37 @@ 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");
 	}
 }
 
@@ -2293,7 +2314,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;
@@ -2326,21 +2349,27 @@ 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 (!json_output)
+			printf("\n");
+
+	if (json_output)
+		printf("}\n");
 
+	if (name)
+		free(name);
 	return 0;
 }
 
@@ -2482,7 +2511,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 = "*";
@@ -2494,25 +2524,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;
 }
@@ -2529,7 +2569,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 */
@@ -2569,60 +2611,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 =
@@ -2630,15 +2621,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;
 }
 
@@ -2716,6 +2707,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;
@@ -2731,7 +2723,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));
@@ -2763,17 +2755,25 @@ 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:
@@ -2787,16 +2787,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");
 
@@ -2812,7 +2807,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]))
@@ -2838,6 +2835,9 @@ static int netlink_show_sock(const struct sockaddr_nl *addr,
 		printf("\n");
 	}
 
+	if (json_output)
+		printf("}\n");
+
 	return 0;
 }
 
@@ -3033,7 +3033,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;
@@ -3045,32 +3045,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");
@@ -3413,11 +3388,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] 14+ messages in thread

* [PATCH v3 07/10] ss: renaming and export of current_filter
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (5 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 06/10] ss: replaced old output mechanisms with fmt handlers interfaces Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 08/10] ss: symmetrical formatter extension example Matthias Tafelmeier
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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>

Conflicts:
	misc/ss.c
---
 misc/ss.c | 220 +++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 110 insertions(+), 110 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 2fbdd7f..c00954d 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)
 {
@@ -1191,7 +1191,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;
@@ -1290,9 +1290,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);
@@ -1306,9 +1306,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);
@@ -3226,19 +3226,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;
@@ -3247,25 +3247,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 {
@@ -3278,9 +3278,9 @@ int main(int argc, char *argv[])
 		{
 			char *p, *p1;
 			if (!saw_query) {
-				current_filter.dbs = 0;
+				ss_current_filter.dbs = 0;
 				state_filter = state_filter ?
-				               state_filter : SS_CONN;
+							state_filter : SS_CONN;
 				saw_query = 1;
 				do_default = 0;
 			}
@@ -3289,44 +3289,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();
@@ -3395,7 +3395,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();
 	}
 
@@ -3421,32 +3421,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);
 		}
@@ -3458,25 +3458,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");
@@ -3484,15 +3484,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;
@@ -3545,90 +3545,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)
@@ -3637,7 +3637,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] 14+ messages in thread

* [PATCH v3 08/10] ss: symmetrical formatter extension example
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (6 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 07/10] ss: renaming and export of current_filter Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 09/10] ss: symmetrical subhandler output " Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 10/10] ss: fixed free on local array for valid json output Matthias Tafelmeier
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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 6955ea5..2051ff2 100644
--- a/misc/ss_hr_fmt.c
+++ b/misc/ss_hr_fmt.c
@@ -240,6 +240,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,
@@ -255,4 +315,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] 14+ messages in thread

* [PATCH v3 09/10] ss: symmetrical subhandler output extension example
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (7 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 08/10] ss: symmetrical formatter extension example Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  2015-08-20 20:40 ` [PATCH v3 10/10] ss: fixed free on local array for valid json output Matthias Tafelmeier
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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).

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

diff --git a/misc/ss_hr_fmt.c b/misc/ss_hr_fmt.c
index 2051ff2..ca73dda 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 3d10220..b08bf86 100644
--- a/misc/ss_json_fmt.c
+++ b/misc/ss_json_fmt.c
@@ -135,6 +135,8 @@ static void tcp_stats_json_fmt(struct tcpstat *s)
 		printf(",\n%s\"reordering\": %d", indent1, s->reordering);
 	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] 14+ messages in thread

* [PATCH v3 10/10] ss: fixed free on local array for valid json output
  2015-08-20 20:40 [PATCH v3]iproute2: full ss json support and general output simplification Matthias Tafelmeier
                   ` (8 preceding siblings ...)
  2015-08-20 20:40 ` [PATCH v3 09/10] ss: symmetrical subhandler output " Matthias Tafelmeier
@ 2015-08-20 20:40 ` Matthias Tafelmeier
  9 siblings, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-20 20:40 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>
---
 misc/ss.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index c00954d..db08c08 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1666,10 +1666,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);
 	}
 }
 
@@ -2368,8 +2364,6 @@ if (show_mem) {
 	if (json_output)
 		printf("}\n");
 
-	if (name)
-		free(name);
 	return 0;
 }
 
-- 
1.9.1

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

* Re: [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters
  2015-08-20 20:40 ` [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters Matthias Tafelmeier
@ 2015-08-23 17:07   ` Stephen Hemminger
  2015-08-24 18:40     ` Matthias Tafelmeier
  2015-08-25 19:13     ` Matthias Tafelmeier
  0 siblings, 2 replies; 14+ messages in thread
From: Stephen Hemminger @ 2015-08-23 17:07 UTC (permalink / raw)
  To: Matthias Tafelmeier; +Cc: netdev, hagen, shemminger, fw, edumazet, daniel

On Thu, 20 Aug 2015 22:40:12 +0200
Matthias Tafelmeier <matthias.tafelmeier@gmx.net> wrote:

> 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>

I looked at this series, and was going to merge it but the code to do
json formatting gets really ugly. Please redo it with the json_writer
code I just added.

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

* Re: [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters
  2015-08-23 17:07   ` Stephen Hemminger
@ 2015-08-24 18:40     ` Matthias Tafelmeier
  2015-08-25 19:13     ` Matthias Tafelmeier
  1 sibling, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-24 18:40 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, hagen, shemminger, fw, edumazet, daniel

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

-----BEGIN PGP MESSAGE-----
Charset: windows-1252
Version: GnuPG v1

hQQOAweL74a5LMkVEA//azcgajmoTO+UKZPf5wl+V8QAi/r9gCmyyJR0wV6RsH0N
sUpnR2c9uSVNU+J41L206vDsnNk0Huoa6m6miibLFg3mxQ9KTDdzaePmkfk9FwCC
Au7RsDzxo8nq/rpZsPeD2r/EAod6C3XVGRNc6nAMMi84tMCtObjDFDQs+mPcWf5n
nCZwmdovGtzCHpw6moq51K8pql0CmRpFSnMdSVySykxc/pFetRBpBJ1hJBT3pCEc
ZYogu5LbKqCbn2xpwXPQDC0i3iEU1sa2xuucj88y8yG9Bdy08mgEwFJvbg+wP83e
oERVIFKIQK02qeS04RgEt5w8t/3b5F3GOn8lqCjLTiXssiKCjgqh0KsdSeE4SwMN
Ny8ND6SOSScCqx1lBvViBGpYw40CdrMwmI5opV0Ljm4lvzmmk8sNcxJhcKQKh/Gq
UYHm0oVMFsoiHlKREKtNn8k8A6fWKes1Psoa2ZsyQfiLH0lSii/eA5OudKYHRw71
oT688HPjABQ7PWjBN7cPr2CqNXutbA7NzvcjmaGZ0aXyd5OMIMyMbPZ4uhWtpN4N
sKtmaxh7kCBnNE50tj65X/hJurEl/tgJeWK8HjOVQOXlqKOTszxZbmvj3Sy0OHRS
RYUSDDaKbgPNeFF67+/ebHlUObo/gt2z9rLZhok9lP8OuXV35Am8qT2INcxsKtEQ
AITEgflrFsR+XG9XQNChtwqsFBx2dULsJqI4QHngtf6OcYNYJ544q6BSe8Meij++
IMAgFdFqyYpgsALsSOqcYbqaL4rxANe+1/gp/71ge9jm/T8vXRIImZuonYvEpJPS
cIvett1uOjmqckI2L4upz3Kx2La5+qhmMmvXxieib8Cmu51WIl9uSHwLsTkZQvyM
oqShZqe/w3zh+3RcuqgaRsTQIpAW5ArS8TvHs5GqYGAo290PxTSYfa70/YmDqkrx
rUGB1Dj7525fMUPACwNU0EemM0ia8ZmpBUWNcEtoPjppROjZ9MsuxDyJHSv7ghre
nTSL1AjcgUmphUsyq/YMD4sxW5k052GgmrQQOEp+LQX6U+r89uDkno3rsgwHCjKb
H7dKL7xqlG3vX8OKsUUvTCQxQIyqCoHxa3Iu6KPyBDq7061A4cNZdE//Jk6kHT0B
lSM50Prkaok+DR5lLBGZ87LVqmqasN/R73m0l+Jz6grMBfaqpUmkyrr3tyQEAZjD
C7IdnY5mrAM/q2GEQDjxk0gHdWBgg1NCNmRdMJ5VEyDtXeDgujnvSJPlTshqhbNE
MTSX9HCdGTwe5L8gEkpcSR7RmZEzPE6Qq4p+lB6cQa8rZlnjuFi7WMXxcivVE4ln
KaAEx+2FSWJ1dAUyLre4aIY//OWz9g2PKsau3U2JcCCxhQQOA+gF559QFX/oEA//
SQPehPCO9VD0sakvFZOCsWN0+65dOlK5hr3rzC2crZeMDaqr9fX7/5IGNHhAaqyc
7SjByXH0f2QC4M2LhR1oA/CihIsWo+0bnmfhJvfnOKrT1KZBqf8irIbdb6vw80e8
0cVE2FhD3WhawMtRv0a1L0eD3iLhz8C9utNe1iRl6hxdu4JKTvqRt7JAjy0dMy4W
4OcviIgMvE6EXmk8hr9LFx17ULGysYswaDBgBW+R1jjp9+EwzyfAmrGbghjtRxJX
4WMn2xYidBWsq3i/86hz0SkENsfrzhc5evOUun8W0yoiJZm6PQcwqsD4nJ8iGbaT
1GrNNdpoyHdQ8F1IXaabkJwVBZXvDxMLTTOKRlapzCEZVOZgirPm562sWY0yQ/9w
Igvv/ufTqLrfU7Wy5tKcuJsDGHdVYaPyusRlOLD65tRQWpDnosAboBB+lpTF13zh
nx4TWO6FqUA74Nc9OslspPz+FOX1vGCrQV6xCnKXP0xOZP3gSJ7yoJlcxhjRnwrf
XfXj2Rh6+V2KrvPsw4PqidBGkNwp1hbd/qB7loFuklt/vRZ02BVEuc3Wo5jDD8Qa
Jct6hwryw3PDu7lI7Zb74CxlzycqhUsHlRtpCXxr6hJepuy8zA1sFKLR8JR+X/u4
QmB1jA+h4WKAXEMuunrEqYitJ4wDrlV6/Kn06H/+K6sP/jjedosIAj46gVXpllu2
MrPVcyo4KQ+uyXhUuq1OeeSGKOmOC70wGrUOZKWTwrXhWMlRgPiiMj1V1/CAHQ2n
7D0ktruvzXf8+rkz2khftz5weke69iHEcjJ9uGiDPYExBGaZQ4SOKdOS2FLz/BWX
o+WhuHJ3R/jgKpkR/KQUKe4ueG0wQOqR8DqIB5D8+PV5NMn7AxXuVLUTsBf0vFoy
BS63QxhPxeD0x9T6SyFwIbpK7h6kr4R67HWvz0Ryu8Dly214IzWTrqzj4j/1ew0e
omKjqyI/+BhHKED7fjfQpmqXhIB492iluzfEeHqXliTxMM+wKdzRdiMeFPwhvI8M
YpEITOwTxvaMMcpA60fvxw39BM4TdnUAyc63O3ebciPENGQq32F9Vj4tAg5IRGMS
BN9HX3dU0PMhCT0UrbNRIWROSGJu43UFqymwffflhJb0xMCqslBsk9qhUqjtEq3A
DLdFt8YZz82uUjqSYyayVr14QdeTj7PhJoX+fOFjWPSLru6jVV7PjekuVfhcILWk
PFyCKYenPdWPyswI7NPmmd4YtovoJTBd0Mzijc2a6S+HJP9FNn3lG1p1L4We/Xcq
ivOvAIRN4NZuHHzTk75WoDsBaL9j+/ddVsyedKfkjo/bQCTnmpR9R3MAibynIT5K
YWUh1wXM2nLqQ/QQL/WHVLUNhQIOA2Nel9d25tJfEAf+JZJbaPnTzw2X04NnnQra
MLdNVys9c6HQUuBUmy6IHN48w5RE8ZXpl8jeiXh8/fyVGM01Ae4oG9Nf3nirAXE3
BW3gncwwEXootoJKeuQfRlVfTi+iHuapw8Bt16CpHe434cBlaeaaN6ZGQmKS8Bgd
vDn3TQn4Bp1gsahDnc9IjSIQMq+sUAeWE97UFrbK0sfs9/81NBTPS5xX8n+r4NEE
mxTHuZIS81aSQHpMc0j2vkZbl6En+JvYa1LcWkw7miIPXN6fGQPjGmw2W4dVoYho
2YwVh0I5mOAYH7kpmJ3bDtIh/DCGRygKqX5xpBBYFUgi0degNM2BXf9Amfcxc+wu
YggAsTXFNzxJZD2mMqyR+VI/2Ep9mJEGYBXUI4cVk6tF480VNYzvSnTeIsUFG2dw
7WXDs4Quon1Myah8ybUfXujvP21y+WG9Kdin9Y2pAtyrJkUdfL8kgQd8leQMHAx0
W+ECgRRcjgXUR5gIGGitYXw2vRfIwMqY7D8N2b5zfhtr94h/7cJORL973C5OAx10
Su4ROx/AU0Q2SWjW/3FwfD2praurLrqTcsD1UvTkW3YX1g5zdZomwYho1v8Qh/rM
R1nYKNcIF9fycGnRsi8F+vqP84uZBtS2p6CRDOSh+9l0iDFAJNwa+lg0abIA4o60
YgFqY6AeJjVwxZ+37ru362r2lIUCDAPlr88g4tbi7QEP/0JYP/q6tqdy6JyVzBu0
+vnc7tNGzEAW42QgYwDRxOebil/ojkhnHxL9tPqToRS76S0i8aI70Z4E7Aq8K/pW
N2QgSNIS2tPdTbVYl9VDidERncLa2eHiCok74H3aR3vLZUC1TGtuvrn2m+PSAzYB
o85whG4nD0sz4HCrqIiR/ASWdkgNc1VGS/0lIeZnfij+WQPN8FvwMFOwKeFlSihs
zIYnT1bzNPe3d+yAhE9C1mOSgFbLs1s287f41moAxvF6OsYtWwyE6y3bE0mDsf2e
0bTSsEFrYmipp9lAgb0C3vCqp8DMrySduk4PEAf/LXkI6wo/TgAlBHHK8YvDlm4E
MEJhUHlt4LkmeEkMTDPtEnuf8DuG0IB8ap4ayQL87hC9N0LrX5hOQVmdWJw5B7Y6
pUIZdOADDT9f/pWNlDu/4bHFAPJNK1S9A2hkhk9FeqTwp4zJCTi7jvHrRad9ckri
rad/V60rOij/OoEYZjbW93mTKyhq48GIU4+az9+S/Cb4RrcSXWf7kyoXmXCB+E7Q
kKS8L+YaLP8q4QuRyUnY/GXDtwu95S0SJ/AJ7y7XLjshcyJ8xdlAJWXFJhAECdJ9
XV/HvxvFAod7L6ag1gHGuzrZRG8SbMTtyiWzDa3FhqtwmvGiSs7/RyDL2wWtV9VD
TRrBGwWaSWsceqRl34UEDVIZhQEMA9VWY3oy9Ed1AQf+NzCoZT1ryrfEI/YzS7sr
J8dUKR2dSdjyX62plHjILQCUET6PEgJeTKRotv0THPLdJDjieTsQqbl5pXdm/T6n
P7hOhC97xZY/Giweabd30ZesAnnnNOW5zBGH8PSpmU3hMnWCsp1Rnp3C2SaeZvxb
Y7QxZRbg+2mb7fp41j3lqiNRczPVldc8iK9ngZSzzMw4MX2mw3BmPwxmD4uUD89y
BuB4J53FMF6TUZe9k38XHgmRLvDq+LYQhf53YNcb/DQ4AB1JHMkitKR1oyI3ptOx
urYuwMNtn2E/EgOqGIbjQrW8JKIUJ8bTgDQiSE7rkZp172+edU1hQYpbfTlAfW0R
zNLpAVd3bBldWfkH29RT2VpxSPbgclAXZGq+ZtBvuTa1p6T3GD0Y95vB70set+w7
oPxjpbjx3zWR/3M6Bz8wla9Bi2qXJ+J87dYRAIK3rYwpnrKfysY+qocJTQiO/Gku
62P2yWKYwcLvRa7v5TwzHxGq0CEul/bzIj8r9ixhReXKGq2PkKEiByqZ900kobMZ
03O4ZXY1FDo9GQ5w6N6T8dPxMuF/hTYADt/8xs1p6RUM+AfljtDdJ1LvBx9pDWjB
KF9ieqOkXw7QPCI7lp9XDv4s0Gqup9bTNOd7doTwc4ah5glnu6IdixGBcrtdQR56
CE96NsHfaKuK0XA9vR0r0LARAFcIRu48EybIUMcEErMIBR+CF9IBmK0DiYvHBgVO
epJzLQ1mgDBdm0cxUjupvLmuNJ6ISGtYHZls2F6b0h2RHwvQcapVzWmt4VgsPXZ4
y/TMAljIxHijyCPhXQ52fUUVTr5LH99oUqhZoqXLOBQ59Aoj/xK/0Mz7JP3R+6eS
c3uuq2/PVNfnr655PAN8BP6/tTfLCaXkeIl60ZQKCEVXymf5gAkVd6bQJpHrSa73
liiN2EAV9yjro+uvF50y1cAzckReSfXkTciIakqyKta1dESuAXelzpdfDXmG5rkC
My7csS+ByP+1FoNmNo8naQc3XCIXUFFWqfnTB/vPXDoi3ywiAfiVpVoctDLX3PyU
0QaIN1IfbZZp8dtPwXejMI5yXXf3aw==
=M0SM
-----END PGP MESSAGE-----

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

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

* Re: [PATCH v3 01/10] ss: rooted out ss type declarations for output formatters
  2015-08-23 17:07   ` Stephen Hemminger
  2015-08-24 18:40     ` Matthias Tafelmeier
@ 2015-08-25 19:13     ` Matthias Tafelmeier
  1 sibling, 0 replies; 14+ messages in thread
From: Matthias Tafelmeier @ 2015-08-25 19:13 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, hagen, shemminger, fw, edumazet, daniel

On 08/23/2015 07:07 PM, Stephen Hemminger wrote:
> On Thu, 20 Aug 2015 22:40:12 +0200
> Matthias Tafelmeier <matthias.tafelmeier@gmx.net> wrote:
> 
>> 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>
> 
> I looked at this series, and was going to merge it but the code to do
> json formatting gets really ugly. Please redo it with the json_writer
> code I just added.
> 

Original: "See your point there. I will do that. Thanks."

Had a glitch with my email-client. This time without PGP.

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

end of thread, other threads:[~2015-08-25 19:13 UTC | newest]

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

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