ss: Add support to filter on device

Add support for device names in the filter. Example:

    root@kenny:~# ss -t  'sport == :22 && dev == red'
    State      Recv-Q Send-Q     Local Address:Port      Peer Address:Port
    ESTAB      0      0          10.100.1.2%red:ssh      10.100.1.254:47814
    ESTAB      0      0           2100:1::2%red:ssh        2100:1::64:49406

Since kernel does not support iface in the filter specifying a
device name means all filtering is done in userspace.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
This commit is contained in:
David Ahern 2016-06-27 11:34:25 -07:00 committed by Stephen Hemminger
parent 376fb86872
commit 2d29321256
3 changed files with 55 additions and 1 deletions

View File

@ -1043,6 +1043,7 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex
struct aafilter {
inet_prefix addr;
int port;
unsigned int iface;
struct aafilter *next;
};
@ -1157,7 +1158,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
return s->lport <= a->port;
}
case SSF_DEVCOND:
{
struct aafilter *a = (void *)f->pred;
return s->iface == a->iface;
}
/* Yup. It is recursion. Sorry. */
case SSF_AND:
return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
@ -1327,6 +1333,11 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
*(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
*bytecode = a;
return l1+4;
}
case SSF_DEVCOND:
{
/* bytecompile for SSF_DEVCOND not supported yet */
return 0;
}
default:
abort();
@ -1416,6 +1427,27 @@ static int xll_name_to_index(const char *dev)
return ll_name_to_index(dev);
}
void *parse_devcond(char *name)
{
struct aafilter a = { .iface = 0 };
struct aafilter *res;
a.iface = xll_name_to_index(name);
if (a.iface == 0) {
char *end;
unsigned long res;
res = strtoul(name, &end, 0);
if (!end || end == name || *end || res > UINT_MAX)
return NULL;
}
res = malloc(sizeof(*res));
*res = a;
return res;
}
void *parse_hostcond(char *addr, bool is_port)
{
char *port = NULL;

View File

@ -8,6 +8,7 @@
#define SSF_S_GE 7
#define SSF_S_LE 8
#define SSF_S_AUTO 9
#define SSF_DEVCOND 10
#include <stdbool.h>
@ -20,3 +21,4 @@ struct ssfilter
int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
void *parse_hostcond(char *addr, bool is_port);
void *parse_devcond(char *name);

View File

@ -36,7 +36,7 @@ static void yyerror(char *s)
%}
%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND
%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME
%left '|'
%left '&'
%nonassoc '!'
@ -108,6 +108,14 @@ expr: DCOND HOSTCOND
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
}
| DEVNAME '=' DEVCOND
{
$$ = alloc_node(SSF_DEVCOND, $3);
}
| DEVNAME NEQ DEVCOND
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3));
}
| AUTOBOUND
{
@ -237,6 +245,10 @@ int yylex(void)
tok_type = SPORT;
return SPORT;
}
if (strcmp(curtok, "dev") == 0) {
tok_type = DEVNAME;
return DEVNAME;
}
if (strcmp(curtok, ">=") == 0 ||
strcmp(curtok, "ge") == 0 ||
strcmp(curtok, "geq") == 0)
@ -263,6 +275,14 @@ int yylex(void)
tok_type = AUTOBOUND;
return AUTOBOUND;
}
if (tok_type == DEVNAME) {
yylval = (void*)parse_devcond(curtok);
if (yylval == NULL) {
fprintf(stderr, "Cannot parse device.\n");
exit(1);
}
return DEVCOND;
}
yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
if (yylval == NULL) {
fprintf(stderr, "Cannot parse dst/src address.\n");