netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iproute2 0/3] ss: Fix sockets filtering
@ 2015-01-03  0:44 Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc Vadim Kochan
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Vadim Kochan @ 2015-01-03  0:44 UTC (permalink / raw)
  To: netdev; +Cc: Vadim Kochan

From: Vadim Kochan <vadim4j@gmail.com>

This series contains refactoring & fixes related to
sockets filtering.

1st 2 patches are related mostly to refactoring as they just
allows to use one func to output UNIX & PACKET socket stats from both Netlink &
/proc.

The last one have a big change which related to the way how filtering options
are combined with each other. This change has also fixes for some filtering
combination options.

I did some basic testing *BUT* I cant guarantee that there is no bugs ...
Here is my some testing list with comparing to the 'master' version:

Some test results with comparing version in PATCH and version from master
-------------------------------------------------------------------------

this   - ss version sending in PATCH
master - ss version in master

Case #1: Show only IPv4 sockets
    $ ss -4

    RESULTS
        this    -  shows only IPv4 sockets with established states     [OK]
        master  -  shows IPv4 and UNIX sockets with established states [FAIL]

Case #2: Show only IPv4 sockets with all states
    $ ss -4 -a

    RESULTS
        this    -  shows only IPv4 sockets with all states [OK]
        master  -  shows ALL sockets kinds with all states [FAIL]

Case #3: Show only IPv4 sockets with listen states (closed or listening)
    $ ss -4 -l

    RESULTS
        this    -  shows only IPv4 sockets with listen states    [OK]
        master  -  shows ALL sockets kinds with LISTENING states [FAIL]

Case #4 Show only IPv4 UDP sockets
    $ ss -4 -u

    RESULTS
        this    -  shows only IPv4 UDP sockets                                 [OK]
        master  -  shows IPv4 UDP sockets but only if state 'closed' specified [FAIL]
    
    In 'this' version it is not needed to set 'closed' state additionally for UDP sockets as it it set
    automatically because we explicitly specified UDP sockets. 

Case #5: Show all UDP sockets
    $ ss -u

    RESULTS
        this    -  shows all UDP sockets for both IPv4/IPv6 protocol families  [OK]
        master  -  shows IPv4 UDP sockets but only if state 'closed' specified [FAIL]

Case #6: Show all UDP sockets for IPv6 only protocol
    $ ss -u -6

    RESULTS
        this    -  shows all IPv6 UDP sockets                                  [OK]
        master  -  shows IPv4 UDP sockets but only if state 'closed' specified [FAIL]


Case #7: Show UNIX sockets with matches "*X11*" as src
    $ ss src unix:*X11*

    RESULTS
        this    -  shows only UNIX sockets with established states with src matches "*X11*" [OK]
        master  -  shows all established UNIX sockets with "RTNETLINK" errors               [FAIL]


Case #8: Show UNIX sockets with matches "*X11*" as src but with LISTENING states only
    $ ss src unix:*X11* -l

    RESULTS
        this    -  shows only UNIX sockets with LISTENING states with src matches "*X11*" [OK]
        master  -  Segmentation error                                                     [FAIL]

Case #9: Show all RAW sockets
    $ ss -w

    RESULTS
        this    - shows all RAW sockets for IPv4/IPv6 families                                  [OK]
        master  - shows all RAW sockets for IPv4/IPv6 families only if state 'closed' specified [FAIL]

Case #10: Show all TCP/UDP sockets
    $ ss -t -u

    RESULTS
        this    - shows all established TCP and unconnected UDP sockets for IPv4/IPv6 protocols. [OK]
        master  - shows only TCP established sockets, shows UDP                                  [FAIL]

Vadim Kochan (3):
  ss: Unify unix stats output from netlink and proc
  ss: Unify packet stats output from netlink and proc
  ss: Filtering logic changing, with fixes

 misc/ss.c | 628 ++++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 346 insertions(+), 282 deletions(-)

-- 
2.1.3

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

* [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc
  2015-01-03  0:44 [PATCH iproute2 0/3] ss: Fix sockets filtering Vadim Kochan
@ 2015-01-03  0:44 ` Vadim Kochan
  2015-01-03 17:56   ` Stephen Hemminger
  2015-01-03  0:44 ` [PATCH iproute2 2/3] ss: Unify packet " Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes Vadim Kochan
  2 siblings, 1 reply; 7+ messages in thread
From: Vadim Kochan @ 2015-01-03  0:44 UTC (permalink / raw)
  To: netdev; +Cc: Vadim Kochan

From: Vadim Kochan <vadim4j@gmail.com>

Refactored to use one func for output unix stats info
from both /proc and netlink.

Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
---
 misc/ss.c | 98 +++++++++++++++++++++++----------------------------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index f0c7b34..a28ca4a 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -2234,6 +2234,7 @@ struct unixstat
 	struct unixstat *next;
 	int ino;
 	int peer;
+	char *peer_name;
 	int rq;
 	int wq;
 	int state;
@@ -2279,7 +2280,18 @@ static const char *unix_netid_name(int type)
 	return netid;
 }
 
-static void unix_list_print(struct unixstat *list, struct filter *f)
+static int unix_type_skip(struct unixstat *s, struct filter *f)
+{
+	if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
+		return 1;
+	if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
+		return 1;
+	if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
+		return 1;
+	return 0;
+}
+
+static void unix_stats_print(struct unixstat *list, struct filter *f)
 {
 	struct unixstat *s;
 	char *peer;
@@ -2287,15 +2299,14 @@ static void unix_list_print(struct unixstat *list, struct filter *f)
 	for (s = list; s; s = s->next) {
 		if (!(f->states & (1<<s->state)))
 			continue;
-		if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
-			continue;
-		if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
-			continue;
-		if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
+		if (unix_type_skip(s, f))
 			continue;
 
 		peer = "*";
-		if (s->peer) {
+		if (s->peer_name)
+			peer = s->peer_name;
+
+		if (s->peer && !s->peer_name) {
 			struct unixstat *p;
 			for (p = list; p; p = p->next) {
 				if (s->peer == p->ino)
@@ -2356,36 +2367,23 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
 	struct unix_diag_msg *r = NLMSG_DATA(nlh);
 	struct rtattr *tb[UNIX_DIAG_MAX+1];
 	char name[128];
-	int peer_ino;
-	__u32 rqlen, wqlen;
+	struct unixstat stat = { .name = "*" , .peer_name = "*" };
 
 	parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
-	if (r->udiag_type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
-		return 0;
-	if (r->udiag_type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
-		return 0;
-	if (r->udiag_type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
-		return 0;
+	stat.type  = r->udiag_type;
+	stat.state = r->udiag_state;
+	stat.ino   = r->udiag_ino;
 
-	if (netid_width)
-		printf("%-*s ", netid_width,
-		       unix_netid_name(r->udiag_type));
-	if (state_width)
-		printf("%-*s ", state_width, sstate_name[r->udiag_state]);
+	if (unix_type_skip(&stat, f))
+		return 0;
 
 	if (tb[UNIX_DIAG_RQLEN]) {
 		struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
-		rqlen = rql->udiag_rqueue;
-		wqlen = rql->udiag_wqueue;
-	} else {
-		rqlen = 0;
-		wqlen = 0;
+		stat.rq = rql->udiag_rqueue;
+		stat.wq = rql->udiag_wqueue;
 	}
-
-	printf("%-6u %-6u ", rqlen, wqlen);
-
 	if (tb[UNIX_DIAG_NAME]) {
 		int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
 
@@ -2393,41 +2391,17 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
 		name[len] = '\0';
 		if (name[0] == '\0')
 			name[0] = '@';
-	} else
-		sprintf(name, "*");
-
+		stat.name = &name[0];
+	}
 	if (tb[UNIX_DIAG_PEER])
-		peer_ino = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
-	else
-		peer_ino = 0;
-
-	printf("%*s %-*d %*s %-*d",
-			addr_width, name,
-			serv_width, r->udiag_ino,
-			addr_width, "*", /* FIXME */
-			serv_width, peer_ino);
-
-	char *buf = NULL;
+		stat.peer = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
 
-	if (show_proc_ctx || show_sock_ctx) {
-		if (find_entry(r->udiag_ino, &buf,
-				(show_proc_ctx & show_sock_ctx) ?
-				PROC_SOCK_CTX : PROC_CTX) > 0) {
-			printf(" users:(%s)", buf);
-			free(buf);
-		}
-	} else if (show_users) {
-		if (find_entry(r->udiag_ino, &buf, USERS) > 0) {
-			printf(" users:(%s)", buf);
-			free(buf);
-		}
-	}
+	unix_stats_print(&stat, f);
 
 	if (show_mem) {
-		printf("\n\t");
+		printf("\t");
 		print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
 	}
-
 	if (show_details) {
 		if (tb[UNIX_DIAG_SHUTDOWN]) {
 			unsigned char mask;
@@ -2435,9 +2409,8 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
 			printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
 		}
 	}
-
-	printf("\n");
-
+	if (show_mem || show_details)
+		printf("\n");
 	return 0;
 }
 
@@ -2505,6 +2478,7 @@ static int unix_show(struct filter *f)
 		if (!(u = malloc(sizeof(*u))))
 			break;
 		u->name = NULL;
+		u->peer_name = NULL;
 
 		if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
 			   &u->peer, &u->rq, &u->wq, &flags, &u->type,
@@ -2544,7 +2518,7 @@ static int unix_show(struct filter *f)
 			strcpy(u->name, name);
 		}
 		if (++cnt > MAX_UNIX_REMEMBER) {
-			unix_list_print(list, f);
+			unix_stats_print(list, f);
 			unix_list_free(list);
 			list = NULL;
 			cnt = 0;
@@ -2552,7 +2526,7 @@ static int unix_show(struct filter *f)
 	}
 	fclose(fp);
 	if (list) {
-		unix_list_print(list, f);
+		unix_stats_print(list, f);
 		unix_list_free(list);
 		list = NULL;
 		cnt = 0;
-- 
2.1.3

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

* [PATCH iproute2 2/3] ss: Unify packet stats output from netlink and proc
  2015-01-03  0:44 [PATCH iproute2 0/3] ss: Fix sockets filtering Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc Vadim Kochan
@ 2015-01-03  0:44 ` Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes Vadim Kochan
  2 siblings, 0 replies; 7+ messages in thread
From: Vadim Kochan @ 2015-01-03  0:44 UTC (permalink / raw)
  To: netdev; +Cc: Vadim Kochan

From: Vadim Kochan <vadim4j@gmail.com>

Refactored to use one func for output packet stats info
from both /proc and netlink.

Added possibility to get packet stats info from /proc
by setting environment variable PROC_ROOT or PROC_NET_PACKET.

Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
---
 misc/ss.c | 215 +++++++++++++++++++++++++++++---------------------------------
 1 file changed, 100 insertions(+), 115 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index a28ca4a..c68af19 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -2535,70 +2535,103 @@ static int unix_show(struct filter *f)
 	return 0;
 }
 
-static int packet_show_sock(const struct sockaddr_nl *addr,
-		struct nlmsghdr *nlh, void *arg)
-{
-	struct packet_diag_msg *r = NLMSG_DATA(nlh);
-	struct rtattr *tb[PACKET_DIAG_MAX+1];
-	__u32 rq;
+struct pktstat {
+	int type;
+	int prot;
+	int iface;
+	int state;
+	int rq;
+	int uid;
+	int ino;
+};
 
-	parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
-		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+static int packet_stats_print(struct pktstat *s, const struct filter *f)
+{
+	char *buf = NULL;
 
-	/* use /proc/net/packet if all info are not available */
-	if (!tb[PACKET_DIAG_MEMINFO])
-		return -1;
+	if (f->f) {
+		struct tcpstat tst;
+		tst.local.family = AF_PACKET;
+		tst.remote.family = AF_PACKET;
+		tst.rport = 0;
+		tst.lport = s->iface;
+		tst.local.data[0] = s->prot;
+		tst.remote.data[0] = 0;
+		if (run_ssfilter(f->f, &tst) == 0)
+			return 1;
+	}
 
 	if (netid_width)
 		printf("%-*s ", netid_width,
-				r->pdiag_type == SOCK_RAW ? "p_raw" : "p_dgr");
+				s->type == SOCK_RAW ? "p_raw" : "p_dgr");
 	if (state_width)
 		printf("%-*s ", state_width, "UNCONN");
 
-	if (tb[PACKET_DIAG_MEMINFO]) {
-		__u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
-
-		rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
-	} else
-		rq = 0;
-	printf("%-6d %-6d ", rq, 0);
-
-	if (r->pdiag_num == 3) {
+	printf("%-6d %-6d ", s->rq, 0);
+	if (s->prot == 3) {
 		printf("%*s:", addr_width, "*");
 	} else {
-		char tb2[16];
+		char tb[16];
 		printf("%*s:", addr_width,
-		       ll_proto_n2a(htons(r->pdiag_num), tb2, sizeof(tb2)));
+				ll_proto_n2a(htons(s->prot), tb, sizeof(tb)));
 	}
-	if (tb[PACKET_DIAG_INFO]) {
-		struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
-
-		if (pinfo->pdi_index == 0)
-			printf("%-*s ", serv_width, "*");
-		else
-			printf("%-*s ", serv_width, xll_index_to_name(pinfo->pdi_index));
-	} else
+	if (s->iface == 0) {
 		printf("%-*s ", serv_width, "*");
+	} else {
+		printf("%-*s ", serv_width, xll_index_to_name(s->iface));
+	}
 
-	printf("%*s*%-*s",
-	       addr_width, "", serv_width, "");
-
-	char *buf = NULL;
+	printf("%*s*%-*s", addr_width, "", serv_width, "");
 
 	if (show_proc_ctx || show_sock_ctx) {
-		if (find_entry(r->pdiag_ino, &buf,
-				(show_proc_ctx & show_sock_ctx) ?
-				PROC_SOCK_CTX : PROC_CTX) > 0) {
+		if (find_entry(s->ino, &buf,
+					(show_proc_ctx & show_sock_ctx) ?
+					PROC_SOCK_CTX : PROC_CTX) > 0) {
 			printf(" users:(%s)", buf);
 			free(buf);
 		}
 	} else if (show_users) {
-		if (find_entry(r->pdiag_ino, &buf, USERS) > 0) {
+		if (find_entry(s->ino, &buf, USERS) > 0) {
 			printf(" users:(%s)", buf);
 			free(buf);
 		}
 	}
 
+	return 0;
+}
+
+static int packet_show_sock(const struct sockaddr_nl *addr,
+		struct nlmsghdr *nlh, void *arg)
+{
+	const struct filter *f = arg;
+	struct packet_diag_msg *r = NLMSG_DATA(nlh);
+	struct rtattr *tb[PACKET_DIAG_MAX+1];
+	struct pktstat stat = {};
+
+	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 */
+	if (!tb[PACKET_DIAG_MEMINFO])
+		return -1;
+
+	stat.type = r->pdiag_type;
+	stat.prot = r->pdiag_num;
+	stat.ino = r->pdiag_ino;
+
+	if (tb[PACKET_DIAG_MEMINFO]) {
+		__u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
+		stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
+	}
+
+	if (tb[PACKET_DIAG_INFO]) {
+		struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
+		stat.iface = pinfo->pdi_index;
+	}
+
+	if (packet_stats_print(&stat, f))
+		return 0;
+
 	if (show_details) {
 		__u32 uid = 0;
 
@@ -2639,94 +2672,46 @@ static int packet_show_netlink(struct filter *f)
 	return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
 }
 
+static int packet_show_line(char *buf, const struct filter *f, int fam)
+{
+	unsigned long long sk;
+	struct pktstat stat = {};
+
+	sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
+			&sk,
+			&stat.type, &stat.prot, &stat.iface, &stat.state,
+			&stat.rq, &stat.uid, &stat.ino);
+
+	if (stat.type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
+		return 0;
+	if (stat.type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
+		return 0;
+
+	if (packet_stats_print(&stat, f))
+		return 0;
+
+	if (show_details) {
+		printf(" ino=%u uid=%u sk=%llx", stat.ino, stat.uid, sk);
+	}
+	printf("\n");
+	return 0;
+}
 
 static int packet_show(struct filter *f)
 {
 	FILE *fp;
-	char buf[256];
-	int type;
-	int prot;
-	int iface;
-	int state;
-	int rq;
-	int uid;
-	int ino;
-	unsigned long long sk;
 
 	if (preferred_family != AF_PACKET && !(f->states & (1 << SS_CLOSE)))
 		return 0;
 
-	if (packet_show_netlink(f) == 0)
+	if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
+			packet_show_netlink(f) == 0)
 		return 0;
 
 	if ((fp = net_packet_open()) == NULL)
 		return -1;
-	fgets(buf, sizeof(buf)-1, fp);
-
-	while (fgets(buf, sizeof(buf)-1, fp)) {
-		sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
-		       &sk,
-		       &type, &prot, &iface, &state,
-		       &rq, &uid, &ino);
-
-		if (type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
-			continue;
-		if (type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
-			continue;
-		if (f->f) {
-			struct tcpstat tst;
-			tst.local.family = AF_PACKET;
-			tst.remote.family = AF_PACKET;
-			tst.rport = 0;
-			tst.lport = iface;
-			tst.local.data[0] = prot;
-			tst.remote.data[0] = 0;
-			if (run_ssfilter(f->f, &tst) == 0)
-				continue;
-		}
-
-		if (netid_width)
-			printf("%-*s ", netid_width,
-			       type == SOCK_RAW ? "p_raw" : "p_dgr");
-		if (state_width)
-			printf("%-*s ", state_width, "UNCONN");
-		printf("%-6d %-6d ", rq, 0);
-		if (prot == 3) {
-			printf("%*s:", addr_width, "*");
-		} else {
-			char tb[16];
-			printf("%*s:", addr_width,
-			       ll_proto_n2a(htons(prot), tb, sizeof(tb)));
-		}
-		if (iface == 0) {
-			printf("%-*s ", serv_width, "*");
-		} else {
-			printf("%-*s ", serv_width, xll_index_to_name(iface));
-		}
-		printf("%*s*%-*s",
-		       addr_width, "", serv_width, "");
-
-		char *buf = NULL;
-
-		if (show_proc_ctx || show_sock_ctx) {
-			if (find_entry(ino, &buf,
-					(show_proc_ctx & show_sock_ctx) ?
-					PROC_SOCK_CTX : PROC_CTX) > 0) {
-				printf(" users:(%s)", buf);
-				free(buf);
-			}
-		} else if (show_users) {
-			if (find_entry(ino, &buf, USERS) > 0) {
-				printf(" users:(%s)", buf);
-				free(buf);
-			}
-		}
-
-		if (show_details) {
-			printf(" ino=%u uid=%u sk=%llx", ino, uid, sk);
-		}
-		printf("\n");
-	}
+	if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
+		return -1;
 
 	return 0;
 }
-- 
2.1.3

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

* [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes
  2015-01-03  0:44 [PATCH iproute2 0/3] ss: Fix sockets filtering Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc Vadim Kochan
  2015-01-03  0:44 ` [PATCH iproute2 2/3] ss: Unify packet " Vadim Kochan
@ 2015-01-03  0:44 ` Vadim Kochan
  2015-01-03 17:57   ` Stephen Hemminger
  2 siblings, 1 reply; 7+ messages in thread
From: Vadim Kochan @ 2015-01-03  0:44 UTC (permalink / raw)
  To: netdev; +Cc: Vadim Kochan

From: Vadim Kochan <vadim4j@gmail.com>

This patch fixes some filtering combinations issues which does not
work on the 'master' version:

    $ ss -4
    shows inet & unix sockets, instead of only inet sockets

    $ ss -u
    needs to specify 'state closed'

    $ ss src unix:*X11*
    needs to specify '-x' shortcut for UNIX family

    $ ss -A all
    shows only sockets with established states

There might some other issues which was not observed.

Also changed logic for calculating families, socket types and
states filtering. I think that this version is a little simpler
one. Now there are 2 predefined default tables which describes
the following maping:

    family  -> (states, dbs)
    db      -> (states, families)

Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
---
 misc/ss.c | 315 +++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 210 insertions(+), 105 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index c68af19..31f316e 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -128,6 +128,7 @@ enum
 #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,
@@ -145,7 +146,8 @@ enum {
 	SS_MAX
 };
 
-#define SS_ALL ((1<<SS_MAX)-1)
+#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"
 
@@ -157,14 +159,120 @@ struct filter
 	struct ssfilter *f;
 };
 
+struct filter default_dbs[MAX_DB] = {
+	[TCP_DB] = {
+		.states   = SS_CONN,
+		.families = (1 << AF_INET) | (1 << AF_INET6),
+	},
+	[DCCP_DB] = {
+		.states   = SS_CONN,
+		.families = (1 << AF_INET) | (1 << AF_INET6),
+	},
+	[UDP_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_INET) | (1 << AF_INET6),
+	},
+	[RAW_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_INET) | (1 << AF_INET6),
+	},
+	[UNIX_DG_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_UNIX),
+	},
+	[UNIX_ST_DB] = {
+		.states   = SS_CONN,
+		.families = (1 << AF_UNIX),
+	},
+	[UNIX_SQ_DB] = {
+		.states   = SS_CONN,
+		.families = (1 << AF_UNIX),
+	},
+	[PACKET_DG_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_PACKET),
+	},
+	[PACKET_R_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_PACKET),
+	},
+	[NETLINK_DB] = {
+		.states   = (1 << SS_CLOSE),
+		.families = (1 << AF_NETLINK),
+	},
+};
+
+struct filter default_afs[AF_MAX] = {
+	[AF_INET] = {
+		.dbs = INET_DBM,
+		.states = SS_CONN,
+	},
+	[AF_INET6] = {
+		.dbs = INET_DBM,
+		.states = SS_CONN,
+	},
+	[AF_UNIX] = {
+		.dbs = UNIX_DBM,
+		.states = SS_CONN,
+	},
+	[AF_PACKET] = {
+		.dbs = PACKET_DBM,
+		.states = (1 << SS_CLOSE),
+	},
+	[AF_NETLINK] = {
+		.dbs = (1 << NETLINK_DB),
+		.states = (1 << SS_CLOSE),
+	},
+};
+
+static int do_default = 1;
 struct filter default_filter = {
-	.dbs	=  ~0,
-	.states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
-	.families= (1<<AF_INET)|(1<<AF_INET6),
+	.dbs	  =  ~0,
+	.states   = SS_CONN,
+	.families = (1 << AF_INET) | (1 << AF_INET6) | (1 << AF_UNIX),
 };
 
 struct filter current_filter;
 
+static void filter_db_set(struct filter *f, int db)
+{
+	f->states   |= default_dbs[db].states;
+	f->families |= default_dbs[db].families;
+	f->dbs	    |= 1 << db;
+	do_default   = 0;
+}
+
+static void filter_af_set(struct filter *f, int af)
+{
+	f->dbs	    |= default_afs[af].dbs;
+	f->states   |= default_afs[af].states;
+	f->families |= 1 << af;
+	do_default   = 0;
+}
+
+static int filter_af_get(struct filter *f, int af)
+{
+	return f->families & (1 << af);
+}
+
+static void filter_merge(struct filter *to, struct filter *from)
+{
+	if (to->families)
+		to->families = (to->families | from->families) & to->families;
+	else
+		to->families |= from->families;
+
+	if (from->dbs)
+		to->dbs = (to->dbs | from->dbs) & from->dbs;
+	else
+		to->dbs |= from->dbs;
+
+	if (from->states)
+		to->states = (to->states | from->states) & from->states;
+	else
+		to->states |= from->states;
+}
+
 static FILE *generic_proc_open(const char *env, const char *name)
 {
 	const char *p = getenv(env);
@@ -1171,12 +1279,13 @@ void *parse_hostcond(char *addr)
 	char *port = NULL;
 	struct aafilter a;
 	struct aafilter *res;
-	int fam = preferred_family;
+	int fam = 0;
+	struct filter *f = &current_filter;
 
 	memset(&a, 0, sizeof(a));
 	a.port = -1;
 
-	if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
+	if (filter_af_get(f, AF_UNIX) || strncmp(addr, "unix:", 5) == 0) {
 		char *p;
 		a.addr.family = AF_UNIX;
 		if (strncmp(addr, "unix:", 5) == 0)
@@ -1184,10 +1293,11 @@ void *parse_hostcond(char *addr)
 		p = strdup(addr);
 		a.addr.bitlen = 8*strlen(p);
 		memcpy(a.addr.data, &p, sizeof(p));
+		fam = AF_UNIX;
 		goto out;
 	}
 
-	if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) {
+	if (filter_af_get(f, AF_PACKET) || strncmp(addr, "link:", 5) == 0) {
 		a.addr.family = AF_PACKET;
 		a.addr.bitlen = 0;
 		if (strncmp(addr, "link:", 5) == 0)
@@ -1209,10 +1319,11 @@ void *parse_hostcond(char *addr)
 				return NULL;
 			a.addr.data[0] = ntohs(tmp);
 		}
+		fam = AF_PACKET;
 		goto out;
 	}
 
-	if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) {
+	if (filter_af_get(f, AF_NETLINK) || strncmp(addr, "netlink:", 8) == 0) {
 		a.addr.family = AF_NETLINK;
 		a.addr.bitlen = 0;
 		if (strncmp(addr, "netlink:", 8) == 0)
@@ -1234,13 +1345,14 @@ void *parse_hostcond(char *addr)
 			if (nl_proto_a2n(&a.addr.data[0], addr) == -1)
 				return NULL;
 		}
+		fam = AF_NETLINK;
 		goto out;
 	}
 
-	if (strncmp(addr, "inet:", 5) == 0) {
+	if (filter_af_get(f, AF_INET) || !strncmp(addr, "inet:", 5)) {
 		addr += 5;
 		fam = AF_INET;
-	} else if (strncmp(addr, "inet6:", 6) == 0) {
+	} else if (filter_af_get(f, AF_INET6) || !strncmp(addr, "inet6:", 6)) {
 		addr += 6;
 		fam = AF_INET6;
 	}
@@ -1309,7 +1421,10 @@ void *parse_hostcond(char *addr)
 		}
 	}
 
-	out:
+out:
+	if (fam)
+		filter_af_set(f, fam);
+
 	res = malloc(sizeof(*res));
 	if (res)
 		memcpy(res, &a, sizeof(a));
@@ -2459,6 +2574,9 @@ static int unix_show(struct filter *f)
 	int  cnt;
 	struct unixstat *list = NULL;
 
+	if (!filter_af_get(f, AF_UNIX))
+		return 0;
+
 	if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
 	    && unix_show_netlink(f) == 0)
 		return 0;
@@ -2701,7 +2819,7 @@ static int packet_show(struct filter *f)
 {
 	FILE *fp;
 
-	if (preferred_family != AF_PACKET && !(f->states & (1 << SS_CLOSE)))
+	if (!filter_af_get(f, AF_PACKET) && !(f->states & (1 << SS_CLOSE)))
 		return 0;
 
 	if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
@@ -2869,7 +2987,7 @@ static int netlink_show(struct filter *f)
 	int rq, wq, rc;
 	unsigned long long sk, cb;
 
-	if (preferred_family != AF_NETLINK && !(f->states & (1 << SS_CLOSE)))
+	if (!filter_af_get(f, AF_NETLINK) && !(f->states & (1 << SS_CLOSE)))
 		return 0;
 
 	if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
@@ -3132,7 +3250,9 @@ static int scan_state(const char *state)
 		if (strcasecmp(state, sstate_namel[i]) == 0)
 			return (1<<i);
 	}
-	return 0;
+
+	fprintf(stderr, "ss: wrong state name: %s\n", state);
+	exit(-1);
 }
 
 static const struct option long_opts[] = {
@@ -3170,13 +3290,14 @@ static const struct option long_opts[] = {
 
 int main(int argc, char *argv[])
 {
-	int do_default = 1;
 	int saw_states = 0;
 	int saw_query = 0;
 	int do_summary = 0;
 	const char *dump_tcpdiag = NULL;
 	FILE *filter_fp = NULL;
 	int ch;
+	struct filter dbs_filter = {};
+	struct filter state_filter = {};
 
 	memset(&current_filter, 0, sizeof(current_filter));
 
@@ -3213,55 +3334,51 @@ int main(int argc, char *argv[])
 			show_bpf++;
 			break;
 		case 'd':
-			current_filter.dbs |= (1<<DCCP_DB);
-			do_default = 0;
+			filter_db_set(&dbs_filter, DCCP_DB);
 			break;
 		case 't':
-			current_filter.dbs |= (1<<TCP_DB);
-			do_default = 0;
+			filter_db_set(&dbs_filter, TCP_DB);
 			break;
 		case 'u':
-			current_filter.dbs |= (1<<UDP_DB);
-			do_default = 0;
+			filter_db_set(&dbs_filter, UDP_DB);
 			break;
 		case 'w':
-			current_filter.dbs |= (1<<RAW_DB);
-			do_default = 0;
+			filter_db_set(&dbs_filter, RAW_DB);
 			break;
 		case 'x':
-			current_filter.dbs |= UNIX_DBM;
-			do_default = 0;
+			filter_af_set(&current_filter, AF_UNIX);
 			break;
 		case 'a':
-			current_filter.states = SS_ALL;
+			state_filter.states = SS_ALL;
 			break;
 		case 'l':
-			current_filter.states = (1<<SS_LISTEN) | (1<<SS_CLOSE);
+			state_filter.states = (1 << SS_LISTEN) | (1 << SS_CLOSE);
 			break;
 		case '4':
-			preferred_family = AF_INET;
+			filter_af_set(&current_filter, AF_INET);
 			break;
 		case '6':
-			preferred_family = AF_INET6;
+			filter_af_set(&current_filter, AF_INET6);
 			break;
 		case '0':
-			preferred_family = AF_PACKET;
+			filter_af_set(&current_filter, AF_PACKET);
 			break;
 		case 'f':
 			if (strcmp(optarg, "inet") == 0)
-				preferred_family = AF_INET;
+				filter_af_set(&current_filter, AF_INET);
 			else if (strcmp(optarg, "inet6") == 0)
-				preferred_family = AF_INET6;
+				filter_af_set(&current_filter, AF_INET6);
 			else if (strcmp(optarg, "link") == 0)
-				preferred_family = AF_PACKET;
+				filter_af_set(&current_filter, AF_PACKET);
 			else if (strcmp(optarg, "unix") == 0)
-				preferred_family = AF_UNIX;
+				filter_af_set(&current_filter, AF_UNIX);
 			else if (strcmp(optarg, "netlink") == 0)
-				preferred_family = AF_NETLINK;
+				filter_af_set(&current_filter, AF_NETLINK);
 			else if (strcmp(optarg, "help") == 0)
 				help();
 			else {
-				fprintf(stderr, "ss: \"%s\" is invalid family\n", optarg);
+				fprintf(stderr, "ss: \"%s\" is invalid family\n",
+						optarg);
 				usage();
 			}
 			break;
@@ -3278,38 +3395,53 @@ int main(int argc, char *argv[])
 				if ((p1 = strchr(p, ',')) != NULL)
 					*p1 = 0;
 				if (strcmp(p, "all") == 0) {
-					current_filter.dbs = ALL_DB;
+					filter_db_set(&dbs_filter, UDP_DB);
+					filter_db_set(&dbs_filter, DCCP_DB);
+					filter_db_set(&dbs_filter, TCP_DB);
+					filter_db_set(&dbs_filter, RAW_DB);
+					filter_db_set(&dbs_filter, UNIX_ST_DB);
+					filter_db_set(&dbs_filter, UNIX_DG_DB);
+					filter_db_set(&dbs_filter, UNIX_SQ_DB);
+					filter_db_set(&dbs_filter, PACKET_R_DB);
+					filter_db_set(&dbs_filter, PACKET_DG_DB);
+					filter_db_set(&dbs_filter, NETLINK_DB);
 				} else if (strcmp(p, "inet") == 0) {
-					current_filter.dbs |= (1<<TCP_DB)|(1<<DCCP_DB)|(1<<UDP_DB)|(1<<RAW_DB);
+					filter_db_set(&dbs_filter, UDP_DB);
+					filter_db_set(&dbs_filter, DCCP_DB);
+					filter_db_set(&dbs_filter, TCP_DB);
+					filter_db_set(&dbs_filter, RAW_DB);
 				} else if (strcmp(p, "udp") == 0) {
-					current_filter.dbs |= (1<<UDP_DB);
+					filter_db_set(&dbs_filter, UDP_DB);
 				} else if (strcmp(p, "dccp") == 0) {
-					current_filter.dbs |= (1<<DCCP_DB);
+					filter_db_set(&dbs_filter, DCCP_DB);
 				} else if (strcmp(p, "tcp") == 0) {
-					current_filter.dbs |= (1<<TCP_DB);
+					filter_db_set(&dbs_filter, TCP_DB);
 				} else if (strcmp(p, "raw") == 0) {
-					current_filter.dbs |= (1<<RAW_DB);
+					filter_db_set(&dbs_filter, RAW_DB);
 				} else if (strcmp(p, "unix") == 0) {
-					current_filter.dbs |= UNIX_DBM;
+					filter_db_set(&dbs_filter, UNIX_ST_DB);
+					filter_db_set(&dbs_filter, UNIX_DG_DB);
+					filter_db_set(&dbs_filter, UNIX_SQ_DB);
 				} else if (strcasecmp(p, "unix_stream") == 0 ||
 					   strcmp(p, "u_str") == 0) {
-					current_filter.dbs |= (1<<UNIX_ST_DB);
+					filter_db_set(&dbs_filter, UNIX_ST_DB);
 				} else if (strcasecmp(p, "unix_dgram") == 0 ||
 					   strcmp(p, "u_dgr") == 0) {
-					current_filter.dbs |= (1<<UNIX_DG_DB);
+					filter_db_set(&dbs_filter, UNIX_DG_DB);
 				} else if (strcasecmp(p, "unix_seqpacket") == 0 ||
 					   strcmp(p, "u_seq") == 0) {
-					current_filter.dbs |= (1<<UNIX_SQ_DB);
+					filter_db_set(&dbs_filter, UNIX_SQ_DB);
 				} else if (strcmp(p, "packet") == 0) {
-					current_filter.dbs |= PACKET_DBM;
+					filter_db_set(&dbs_filter, PACKET_R_DB);
+					filter_db_set(&dbs_filter, PACKET_DG_DB);
 				} else if (strcmp(p, "packet_raw") == 0 ||
 					   strcmp(p, "p_raw") == 0) {
-					current_filter.dbs |= (1<<PACKET_R_DB);
+					filter_db_set(&dbs_filter, PACKET_R_DB);
 				} else if (strcmp(p, "packet_dgram") == 0 ||
 					   strcmp(p, "p_dgr") == 0) {
-					current_filter.dbs |= (1<<PACKET_DG_DB);
+					filter_db_set(&dbs_filter, PACKET_DG_DB);
 				} else if (strcmp(p, "netlink") == 0) {
-					current_filter.dbs |= (1<<NETLINK_DB);
+					filter_db_set(&dbs_filter, NETLINK_DB);
 				} else {
 					fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
 					usage();
@@ -3371,57 +3503,6 @@ int main(int argc, char *argv[])
 			exit(0);
 	}
 
-	if (do_default)
-		current_filter.dbs = default_filter.dbs;
-
-	if (preferred_family == AF_UNSPEC) {
-		if (!(current_filter.dbs&~UNIX_DBM))
-			preferred_family = AF_UNIX;
-		else if (!(current_filter.dbs&~PACKET_DBM))
-			preferred_family = AF_PACKET;
-		else if (!(current_filter.dbs&~(1<<NETLINK_DB)))
-			preferred_family = AF_NETLINK;
-	}
-
-	if (preferred_family != AF_UNSPEC) {
-		int mask2;
-		if (preferred_family == AF_INET ||
-		    preferred_family == AF_INET6) {
-			mask2= current_filter.dbs;
-		} else if (preferred_family == AF_PACKET) {
-			mask2 = PACKET_DBM;
-		} else if (preferred_family == AF_UNIX) {
-			mask2 = UNIX_DBM;
-		} else if (preferred_family == AF_NETLINK) {
-			mask2 = (1<<NETLINK_DB);
-		} else {
-			mask2 = 0;
-		}
-
-		if (do_default)
-			current_filter.dbs = mask2;
-		else
-			current_filter.dbs &= mask2;
-		current_filter.families = (1<<preferred_family);
-	} else {
-		if (!do_default)
-			current_filter.families = ~0;
-		else
-			current_filter.families = default_filter.families;
-	}
-	if (current_filter.dbs == 0) {
-		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
-		exit(0);
-	}
-	if (current_filter.families == 0) {
-		fprintf(stderr, "ss: no families to show with such filter.\n");
-		exit(0);
-	}
-
-	if (resolve_services && resolve_hosts &&
-	    (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
-		init_service_resolver();
-
 	/* Now parse filter... */
 	if (argc == 0 && filter_fp) {
 		if (ssfilter_parse(&current_filter.f, 0, NULL, filter_fp))
@@ -3432,15 +3513,15 @@ int main(int argc, char *argv[])
 		if (strcmp(*argv, "state") == 0) {
 			NEXT_ARG();
 			if (!saw_states)
-				current_filter.states = 0;
-			current_filter.states |= scan_state(*argv);
+				state_filter.states = 0;
+			state_filter.states |= scan_state(*argv);
 			saw_states = 1;
 		} else if (strcmp(*argv, "exclude") == 0 ||
 			   strcmp(*argv, "excl") == 0) {
 			NEXT_ARG();
 			if (!saw_states)
-				current_filter.states = SS_ALL;
-			current_filter.states &= ~scan_state(*argv);
+				state_filter.states = SS_ALL;
+			state_filter.states &= ~scan_state(*argv);
 			saw_states = 1;
 		} else {
 			if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
@@ -3450,6 +3531,30 @@ int main(int argc, char *argv[])
 		argc--; argv++;
 	}
 
+	if (do_default) {
+		current_filter.dbs = default_filter.dbs;
+		current_filter.families = default_filter.families;
+	} else {
+		filter_merge(&current_filter, &dbs_filter);
+	}
+
+	state_filter.dbs      = current_filter.dbs;
+	state_filter.families = current_filter.families;
+	filter_merge(&current_filter, &state_filter);
+
+	if (resolve_services && resolve_hosts &&
+	    (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);
+	}
+	if (current_filter.families == 0) {
+		fprintf(stderr, "ss: no families to show with such filter.\n");
+		exit(0);
+	}
 	if (current_filter.states == 0) {
 		fprintf(stderr, "ss: no socket states to show with such filter.\n");
 		exit(0);
-- 
2.1.3

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

* Re: [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc
  2015-01-03  0:44 ` [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc Vadim Kochan
@ 2015-01-03 17:56   ` Stephen Hemminger
  0 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2015-01-03 17:56 UTC (permalink / raw)
  To: Vadim Kochan; +Cc: netdev

Looks good, but could you fix some minor style things.

On Sat,  3 Jan 2015 02:44:35 +0200
Vadim Kochan <vadim4j@gmail.com> wrote:

>  
> -static void unix_list_print(struct unixstat *list, struct filter *f)
> +static int unix_type_skip(struct unixstat *s, struct filter *f)
> +{

Please use bool for logical true/false value in new code.

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

* Re: [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes
  2015-01-03  0:44 ` [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes Vadim Kochan
@ 2015-01-03 17:57   ` Stephen Hemminger
  2015-01-03 22:58     ` Vadim Kochan
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Hemminger @ 2015-01-03 17:57 UTC (permalink / raw)
  To: Vadim Kochan; +Cc: netdev

On Sat,  3 Jan 2015 02:44:37 +0200
Vadim Kochan <vadim4j@gmail.com> wrote:

> +struct filter default_dbs[MAX_DB] = {
> +	[TCP_DB] = {
> +		.states   = SS_CONN,
> +		.families = (1 << AF_INET) | (1 << AF_INET6),
> +	},

I like table driven code, so this is good. But please make
mark the table as const.

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

* Re: [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes
  2015-01-03 17:57   ` Stephen Hemminger
@ 2015-01-03 22:58     ` Vadim Kochan
  0 siblings, 0 replies; 7+ messages in thread
From: Vadim Kochan @ 2015-01-03 22:58 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Vadim Kochan, netdev

On Sat, Jan 03, 2015 at 09:57:07AM -0800, Stephen Hemminger wrote:
> On Sat,  3 Jan 2015 02:44:37 +0200
> Vadim Kochan <vadim4j@gmail.com> wrote:
> 
> > +struct filter default_dbs[MAX_DB] = {
> > +	[TCP_DB] = {
> > +		.states   = SS_CONN,
> > +		.families = (1 << AF_INET) | (1 << AF_INET6),
> > +	},
> 
> I like table driven code, so this is good. But please make
> mark the table as const.

I did re-test, and I still don't like very much my results (some cases
are not logically) even if they (IMHO) better than the 'master' version,
so I will try to change filer options applying in the following way:

    0) default filter should have only default states & all dbs

    1) apply all selected families with their default dbs & states from table

    2) logical AND selected dbs with dbs of the selected families and their default
        states from table, also select families by db from table if there no
        already selected families

    3) logical AND selected states with selected dbs and their default states from table,
        also select families and dbs from table by states if there no
        already selected dbs & families

So with such approach the options should affect each other in the strict
predictable way:

    families -> dbs (socket tables) -> socket states

I hope I will success with this ...

I appreciate any feedback.

Regards,
Vadim Kochan

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

end of thread, other threads:[~2015-01-03 23:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-03  0:44 [PATCH iproute2 0/3] ss: Fix sockets filtering Vadim Kochan
2015-01-03  0:44 ` [PATCH iproute2 1/3] ss: Unify unix stats output from netlink and proc Vadim Kochan
2015-01-03 17:56   ` Stephen Hemminger
2015-01-03  0:44 ` [PATCH iproute2 2/3] ss: Unify packet " Vadim Kochan
2015-01-03  0:44 ` [PATCH iproute2 3/3] ss: Filtering logic changing, with fixes Vadim Kochan
2015-01-03 17:57   ` Stephen Hemminger
2015-01-03 22:58     ` Vadim Kochan

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