mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-05 17:15:45 +00:00
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:
parent
376fb86872
commit
2d29321256
32
misc/ss.c
32
misc/ss.c
@ -1043,6 +1043,7 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex
|
|||||||
struct aafilter {
|
struct aafilter {
|
||||||
inet_prefix addr;
|
inet_prefix addr;
|
||||||
int port;
|
int port;
|
||||||
|
unsigned int iface;
|
||||||
struct aafilter *next;
|
struct aafilter *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1157,7 +1158,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
|
|||||||
|
|
||||||
return s->lport <= a->port;
|
return s->lport <= a->port;
|
||||||
}
|
}
|
||||||
|
case SSF_DEVCOND:
|
||||||
|
{
|
||||||
|
struct aafilter *a = (void *)f->pred;
|
||||||
|
|
||||||
|
return s->iface == a->iface;
|
||||||
|
}
|
||||||
/* Yup. It is recursion. Sorry. */
|
/* Yup. It is recursion. Sorry. */
|
||||||
case SSF_AND:
|
case SSF_AND:
|
||||||
return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
|
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 };
|
*(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
|
||||||
*bytecode = a;
|
*bytecode = a;
|
||||||
return l1+4;
|
return l1+4;
|
||||||
|
}
|
||||||
|
case SSF_DEVCOND:
|
||||||
|
{
|
||||||
|
/* bytecompile for SSF_DEVCOND not supported yet */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
@ -1416,6 +1427,27 @@ static int xll_name_to_index(const char *dev)
|
|||||||
return ll_name_to_index(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)
|
void *parse_hostcond(char *addr, bool is_port)
|
||||||
{
|
{
|
||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define SSF_S_GE 7
|
#define SSF_S_GE 7
|
||||||
#define SSF_S_LE 8
|
#define SSF_S_LE 8
|
||||||
#define SSF_S_AUTO 9
|
#define SSF_S_AUTO 9
|
||||||
|
#define SSF_DEVCOND 10
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -20,3 +21,4 @@ struct ssfilter
|
|||||||
|
|
||||||
int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
|
int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
|
||||||
void *parse_hostcond(char *addr, bool is_port);
|
void *parse_hostcond(char *addr, bool is_port);
|
||||||
|
void *parse_devcond(char *name);
|
||||||
|
@ -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 '|'
|
||||||
%left '&'
|
%left '&'
|
||||||
%nonassoc '!'
|
%nonassoc '!'
|
||||||
@ -108,6 +108,14 @@ expr: DCOND HOSTCOND
|
|||||||
{
|
{
|
||||||
$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
|
$$ = 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
|
| AUTOBOUND
|
||||||
{
|
{
|
||||||
@ -237,6 +245,10 @@ int yylex(void)
|
|||||||
tok_type = SPORT;
|
tok_type = SPORT;
|
||||||
return SPORT;
|
return SPORT;
|
||||||
}
|
}
|
||||||
|
if (strcmp(curtok, "dev") == 0) {
|
||||||
|
tok_type = DEVNAME;
|
||||||
|
return DEVNAME;
|
||||||
|
}
|
||||||
if (strcmp(curtok, ">=") == 0 ||
|
if (strcmp(curtok, ">=") == 0 ||
|
||||||
strcmp(curtok, "ge") == 0 ||
|
strcmp(curtok, "ge") == 0 ||
|
||||||
strcmp(curtok, "geq") == 0)
|
strcmp(curtok, "geq") == 0)
|
||||||
@ -263,6 +275,14 @@ int yylex(void)
|
|||||||
tok_type = AUTOBOUND;
|
tok_type = AUTOBOUND;
|
||||||
return 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);
|
yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
|
||||||
if (yylval == NULL) {
|
if (yylval == NULL) {
|
||||||
fprintf(stderr, "Cannot parse dst/src address.\n");
|
fprintf(stderr, "Cannot parse dst/src address.\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user