diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2016-09-24 01:48:10 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-09-24 01:48:10 +0000 |
commit | db25ccb0714ef18693a91698d0d0eba1446c7793 (patch) | |
tree | f35c1a92fdf0b707b4812a898c83521c3733c082 | |
parent | fb80ac03aff71033570e1b13cd52bdfa9e60e6a0 (diff) | |
parent | d4db01bf3fe57ba65af116cfa399f89f90002ba7 (diff) | |
download | iproute2-nougat-mr1-wear-release.tar.gz |
ss: Support displaying and filtering on socket marks.android-wear-7.1.1_r1android-7.1.2_r9android-7.1.2_r8android-7.1.2_r6android-7.1.2_r5android-7.1.2_r4android-7.1.2_r39android-7.1.2_r38android-7.1.2_r37android-7.1.2_r36android-7.1.2_r33android-7.1.2_r32android-7.1.2_r30android-7.1.2_r3android-7.1.2_r29android-7.1.2_r28android-7.1.2_r27android-7.1.2_r25android-7.1.2_r24android-7.1.2_r23android-7.1.2_r2android-7.1.2_r19android-7.1.2_r18android-7.1.2_r17android-7.1.2_r16android-7.1.2_r15android-7.1.2_r14android-7.1.2_r13android-7.1.2_r12android-7.1.2_r11android-7.1.2_r10android-7.1.2_r1nougat-mr2.3-releasenougat-mr2.2-releasenougat-mr2.1-releasenougat-mr2-security-releasenougat-mr2-releasenougat-mr2-pixel-releasenougat-mr2-devnougat-mr1-wear-release
am: d4db01bf3f
Change-Id: Ic786233b6864b4510778813d76155de258a46406
-rw-r--r-- | include/linux/inet_diag.h | 14 | ||||
-rw-r--r-- | misc/ss.c | 51 | ||||
-rw-r--r-- | misc/ssfilter.h | 2 | ||||
-rw-r--r-- | misc/ssfilter.y | 23 |
4 files changed, 87 insertions, 3 deletions
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 1db41168..016de886 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -72,6 +72,8 @@ enum { INET_DIAG_BC_AUTO, INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND, + INET_DIAG_BC_DEV_COND, /* u32 ifindex */ + INET_DIAG_BC_MARK_COND, }; struct inet_diag_hostcond { @@ -81,6 +83,11 @@ struct inet_diag_hostcond { __be32 addr[0]; }; +struct inet_diag_markcond { + __u32 mark; + __u32 mask; +}; + /* Base info structure. It contains socket identity (addrs/ports/cookie) * and, alas, the information shown by netstat. */ struct inet_diag_msg { @@ -113,9 +120,14 @@ enum { INET_DIAG_DCTCPINFO, INET_DIAG_PROTOCOL, /* response attribute only */ INET_DIAG_SKV6ONLY, + INET_DIAG_LOCALS, + INET_DIAG_PEERS, + INET_DIAG_PAD, + INET_DIAG_MARK, + __INET_DIAG_MAX, }; -#define INET_DIAG_MAX INET_DIAG_SKV6ONLY +#define INET_DIAG_MAX (__INET_DIAG_MAX - 1) /* INET_DIAG_MEM */ @@ -738,6 +738,7 @@ struct sockstat unsigned long long sk; char *name; char *peer_name; + __u32 mark; }; struct dctcpstat @@ -806,6 +807,9 @@ static void sock_details_print(struct sockstat *s) printf(" ino:%u", s->ino); printf(" sk:%llx", s->sk); + + if (s->mark) + printf(" fwmark:0x%x", s->mark); } static void sock_addr_print_width(int addr_len, const char *addr, char *delim, @@ -1043,6 +1047,8 @@ struct aafilter { inet_prefix addr; int port; + __u32 mark; + __u32 mask; struct aafilter *next; }; @@ -1148,7 +1154,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) struct aafilter *a = (void*)f->pred; return s->lport <= a->port; } + case SSF_MARKMASK: + { + struct aafilter *a = (void *)f->pred; + return (s->mark & a->mask) == a->mark; + } /* Yup. It is recursion. Sorry. */ case SSF_AND: return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s); @@ -1297,6 +1308,23 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) *bytecode = a; return l1+4; } + case SSF_MARKMASK: + { + struct aafilter *a = (void *)f->pred; + struct instr { + struct inet_diag_bc_op op; + struct inet_diag_markcond cond; + }; + int inslen = sizeof(struct instr); + + if (!(*bytecode = malloc(inslen))) abort(); + ((struct instr *)*bytecode)[0] = (struct instr) { + { INET_DIAG_BC_MARK_COND, inslen, inslen + 4 }, + { a->mark, a->mask}, + }; + + return inslen; + } default: abort(); } @@ -1546,6 +1574,25 @@ out: return res; } +void *parse_markmask(const char *markmask) +{ + struct aafilter a, *res; + + if (strchr(markmask, '/')) { + if (sscanf(markmask, "%i/%i", &a.mark, &a.mask) != 2) + return NULL; + } else { + a.mask = 0xffffffff; + if (sscanf(markmask, "%i", &a.mark) != 1) + return NULL; + } + + res = malloc(sizeof(*res)); + if (res) + memcpy(res, &a, sizeof(a)); + return res; +} + static char *proto_name(int protocol) { switch (protocol) { @@ -2015,6 +2062,10 @@ 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]); + s.mark = 0; + if (tb[INET_DIAG_MARK]) + s.mark = *(__u32 *) RTA_DATA(tb[INET_DIAG_MARK]); + if (s.local.family == AF_INET) { s.local.bytelen = s.remote.bytelen = 4; } else { diff --git a/misc/ssfilter.h b/misc/ssfilter.h index 53922a84..c7293cc0 100644 --- a/misc/ssfilter.h +++ b/misc/ssfilter.h @@ -8,6 +8,7 @@ #define SSF_S_GE 7 #define SSF_S_LE 8 #define SSF_S_AUTO 9 +#define SSF_MARKMASK 11 #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_markmask(const char *markmask); diff --git a/misc/ssfilter.y b/misc/ssfilter.y index 9906ad86..ba6b06f3 100644 --- a/misc/ssfilter.y +++ b/misc/ssfilter.y @@ -39,7 +39,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 MARKMASK FWMARK %left '|' %left '&' %nonassoc '!' @@ -111,7 +111,14 @@ expr: DCOND HOSTCOND { $$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3)); } - + | FWMARK '=' MARKMASK + { + $$ = alloc_node(SSF_MARKMASK, $3); + } + | FWMARK NEQ MARKMASK + { + $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3)); + } | AUTOBOUND { $$ = alloc_node(SSF_S_AUTO, NULL); @@ -240,6 +247,10 @@ int yylex(void) tok_type = SPORT; return SPORT; } + if (strcmp(curtok, "fwmark") == 0) { + tok_type = FWMARK; + return FWMARK; + } if (strcmp(curtok, ">=") == 0 || strcmp(curtok, "ge") == 0 || strcmp(curtok, "geq") == 0) @@ -266,6 +277,14 @@ int yylex(void) tok_type = AUTOBOUND; return AUTOBOUND; } + if (tok_type == FWMARK) { + yylval = (void*)parse_markmask(curtok); + if (yylval == NULL) { + fprintf(stderr, "Cannot parse mark %s.\n", curtok); + exit(1); + } + return MARKMASK; + } yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT); if (yylval == NULL) { fprintf(stderr, "Cannot parse dst/src address.\n"); |