From 82d73ea03a1495a51425c28025ae48f92fb19182 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:23 -0700 Subject: [PATCH 1/9] ss: Refactor inet_show_sock Extract parsing of sockstat and filter from inet_show_sock. While moving run_ssfilter into callers of inet_show_sock enable userspace filtering before the kill. Signed-off-by: David Ahern --- misc/ss.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 02be7e74..f164ca92 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2038,42 +2038,48 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, } } -static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) +static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s) { struct rtattr *tb[INET_DIAG_MAX+1]; struct inet_diag_msg *r = NLMSG_DATA(nlh); - struct sockstat s = {}; parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); - s.state = r->idiag_state; - s.local.family = s.remote.family = r->idiag_family; - s.lport = ntohs(r->id.idiag_sport); - s.rport = ntohs(r->id.idiag_dport); - s.wq = r->idiag_wqueue; - s.rq = r->idiag_rqueue; - s.ino = r->idiag_inode; - s.uid = r->idiag_uid; - s.iface = r->id.idiag_if; - s.sk = cookie_sk_get(&r->id.idiag_cookie[0]); + s->state = r->idiag_state; + s->local.family = s->remote.family = r->idiag_family; + s->lport = ntohs(r->id.idiag_sport); + s->rport = ntohs(r->id.idiag_dport); + s->wq = r->idiag_wqueue; + s->rq = r->idiag_rqueue; + s->ino = r->idiag_inode; + s->uid = r->idiag_uid; + s->iface = r->id.idiag_if; + s->sk = cookie_sk_get(&r->id.idiag_cookie[0]); - if (s.local.family == AF_INET) { - s.local.bytelen = s.remote.bytelen = 4; - } else { - s.local.bytelen = s.remote.bytelen = 16; - } + if (s->local.family == AF_INET) + s->local.bytelen = s->remote.bytelen = 4; + else + s->local.bytelen = s->remote.bytelen = 16; - memcpy(s.local.data, r->id.idiag_src, s.local.bytelen); - memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen); + memcpy(s->local.data, r->id.idiag_src, s->local.bytelen); + memcpy(s->remote.data, r->id.idiag_dst, s->local.bytelen); +} - if (f && f->f && run_ssfilter(f->f, &s) == 0) - return 0; +static int inet_show_sock(struct nlmsghdr *nlh, + struct sockstat *s, + int protocol) +{ + struct rtattr *tb[INET_DIAG_MAX+1]; + struct inet_diag_msg *r = NLMSG_DATA(nlh); + + parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1), + nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[INET_DIAG_PROTOCOL]) protocol = *(__u8 *)RTA_DATA(tb[INET_DIAG_PROTOCOL]); - inet_stats_print(&s, protocol); + inet_stats_print(s, protocol); if (show_options) { struct tcpstat t = {}; @@ -2085,8 +2091,8 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) } if (show_details) { - sock_details_print(&s); - if (s.local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) { + 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]); @@ -2268,9 +2274,16 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, int err; struct inet_diag_arg *diag_arg = arg; struct inet_diag_msg *r = NLMSG_DATA(h); + struct sockstat s = {}; if (!(diag_arg->f->families & (1 << r->idiag_family))) return 0; + + parse_diag_msg(h, &s); + + if (diag_arg->f->f && run_ssfilter(diag_arg->f->f, &s) == 0) + return 0; + if (diag_arg->f->kill && kill_inet_sock(h, arg) != 0) { if (errno == EOPNOTSUPP || errno == ENOENT) { /* Socket can't be closed, or is already closed. */ @@ -2280,7 +2293,9 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, return -1; } } - if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0) + + err = inet_show_sock(h, &s, diag_arg->protocol); + if (err < 0) return err; return 0; @@ -2345,6 +2360,7 @@ static int tcp_show_netlink_file(struct filter *f) while (1) { int status, err; struct nlmsghdr *h = (struct nlmsghdr *)buf; + struct sockstat s = {}; status = fread(buf, 1, sizeof(*h), fp); if (status < 0) { @@ -2383,7 +2399,12 @@ static int tcp_show_netlink_file(struct filter *f) return -1; } - err = inet_show_sock(h, f, IPPROTO_TCP); + parse_diag_msg(h, &s); + + if (f && f->f && run_ssfilter(f->f, &s) == 0) + continue; + + err = inet_show_sock(h, &s, IPPROTO_TCP); if (err < 0) return err; } From 376fb86872c06a34e59d681661b8f66adaeb6815 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:24 -0700 Subject: [PATCH 2/9] ss: Allow ssfilter_bytecompile to return 0 Allow ssfilter_bytecompile to return 0 for filter ops the kernel does not support. If such an op is in the filter string then all filtering is done in userspace. Signed-off-by: David Ahern --- misc/ss.c | 52 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index f164ca92..05107016 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1273,11 +1273,16 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) case SSF_AND: { - char *a1, *a2, *a; + char *a1 = NULL, *a2 = NULL, *a; int l1, l2; l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); + if (!l1 || !l2) { + free(a1); + free(a2); + return 0; + } if (!(a = malloc(l1+l2))) abort(); memcpy(a, a1, l1); memcpy(a+l1, a2, l2); @@ -1288,11 +1293,16 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } case SSF_OR: { - char *a1, *a2, *a; + char *a1 = NULL, *a2 = NULL, *a; int l1, l2; l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); + if (!l1 || !l2) { + free(a1); + free(a2); + return 0; + } if (!(a = malloc(l1+l2+4))) abort(); memcpy(a, a1, l1); memcpy(a+l1+4, a2, l2); @@ -1303,10 +1313,14 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } case SSF_NOT: { - char *a1, *a; + char *a1 = NULL, *a; int l1; l1 = ssfilter_bytecompile(f->pred, &a1); + if (!l1) { + free(a1); + return 0; + } if (!(a = malloc(l1+4))) abort(); memcpy(a, a1, l1); free(a1); @@ -2127,6 +2141,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) struct msghdr msg; struct rtattr rta; struct iovec iov[3]; + int iovlen = 1; if (protocol == IPPROTO_UDP) return -1; @@ -2162,18 +2177,21 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) }; if (f->f) { bclen = ssfilter_bytecompile(f->f, &bc); - rta.rta_type = INET_DIAG_REQ_BYTECODE; - rta.rta_len = RTA_LENGTH(bclen); - iov[1] = (struct iovec){ &rta, sizeof(rta) }; - iov[2] = (struct iovec){ bc, bclen }; - req.nlh.nlmsg_len += RTA_LENGTH(bclen); + if (bclen) { + rta.rta_type = INET_DIAG_REQ_BYTECODE; + rta.rta_len = RTA_LENGTH(bclen); + iov[1] = (struct iovec){ &rta, sizeof(rta) }; + iov[2] = (struct iovec){ bc, bclen }; + req.nlh.nlmsg_len += RTA_LENGTH(bclen); + iovlen = 3; + } } msg = (struct msghdr) { .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, - .msg_iovlen = f->f ? 3 : 1, + .msg_iovlen = iovlen, }; if (sendmsg(fd, &msg, 0) < 0) { @@ -2194,6 +2212,7 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) struct msghdr msg; struct rtattr rta; struct iovec iov[3]; + int iovlen = 1; if (family == PF_UNSPEC) return tcpdiag_send(fd, protocol, f); @@ -2222,18 +2241,21 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) }; if (f->f) { bclen = ssfilter_bytecompile(f->f, &bc); - rta.rta_type = INET_DIAG_REQ_BYTECODE; - rta.rta_len = RTA_LENGTH(bclen); - iov[1] = (struct iovec){ &rta, sizeof(rta) }; - iov[2] = (struct iovec){ bc, bclen }; - req.nlh.nlmsg_len += RTA_LENGTH(bclen); + if (bclen) { + rta.rta_type = INET_DIAG_REQ_BYTECODE; + rta.rta_len = RTA_LENGTH(bclen); + iov[1] = (struct iovec){ &rta, sizeof(rta) }; + iov[2] = (struct iovec){ bc, bclen }; + req.nlh.nlmsg_len += RTA_LENGTH(bclen); + iovlen = 3; + } } msg = (struct msghdr) { .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, - .msg_iovlen = f->f ? 3 : 1, + .msg_iovlen = iovlen, }; if (sendmsg(fd, &msg, 0) < 0) { From 2d29321256168e13e10fbde3c57f33e70dcb6cc8 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:25 -0700 Subject: [PATCH 3/9] 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 --- misc/ss.c | 32 ++++++++++++++++++++++++++++++++ misc/ssfilter.h | 2 ++ misc/ssfilter.y | 22 +++++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index 05107016..20ea3a44 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -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; diff --git a/misc/ssfilter.h b/misc/ssfilter.h index 53922a84..c7db8eee 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_DEVCOND 10 #include @@ -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); diff --git a/misc/ssfilter.y b/misc/ssfilter.y index a258d04b..14bf9817 100644 --- a/misc/ssfilter.y +++ b/misc/ssfilter.y @@ -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"); From 62000e51e05d635016bae9891a4e00134ed8aefb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 18:42:15 +0200 Subject: [PATCH 4/9] Use ARRAY_SIZE macro everywhere This patch was generated by the following semantic patch (a trimmed down version of what is shipped with Linux sources): @@ type T; T[] E; @@ ( - (sizeof(E)/sizeof(*E)) + ARRAY_SIZE(E) | - (sizeof(E)/sizeof(E[...])) + ARRAY_SIZE(E) | - (sizeof(E)/sizeof(T)) + ARRAY_SIZE(E) ) The only manual adjustment was to include utils.h in misc/nstat.c to make the macro known there. Signed-off-by: Phil Sutter --- bridge/link.c | 2 +- misc/nstat.c | 3 ++- misc/ss.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bridge/link.c b/bridge/link.c index 353e1c3d..b347040c 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -319,7 +319,7 @@ static int brlink_modify(int argc, char **argv) } else if (strcmp(*argv, "state") == 0) { NEXT_ARG(); char *endptr; - size_t nstates = sizeof(port_states) / sizeof(*port_states); + size_t nstates = ARRAY_SIZE(port_states); state = strtol(*argv, &endptr, 10); if (!(**argv != '\0' && *endptr == '\0')) { diff --git a/misc/nstat.c b/misc/nstat.c index a9e0f207..e579ce1d 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -30,6 +30,7 @@ #include #include +#include "utils.h" int dump_zeros; int reset_history; @@ -95,7 +96,7 @@ static int useless_number(const char *id) { int i; - for (i = 0; i < sizeof(useless_numbers)/sizeof(*useless_numbers); i++) + for (i = 0; i < ARRAY_SIZE(useless_numbers); i++) if (strcmp(id, useless_numbers[i]) == 0) return 1; return 0; diff --git a/misc/ss.c b/misc/ss.c index 20ea3a44..a0f9c6b9 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -666,7 +666,7 @@ static int get_slabstat(struct slabstat *s) while (fgets(buf, sizeof(buf), fp) != NULL) { int i; - for (i = 0; i < sizeof(slabstat_ids)/sizeof(slabstat_ids[0]); i++) { + for (i = 0; i < ARRAY_SIZE(slabstat_ids); i++) { if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) { sscanf(buf, "%*s%d", ((int *)s) + i); cnt--; From e0513807f6dbbd4631fdbb27f0bd6bbce138e8cd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 15:07:16 +0200 Subject: [PATCH 5/9] ip-address: Support filtering by slave type, too This patch allows to query all interfaces enslaved to a bridge or bond using the following syntax: | ip addr show type bridge_slave Filtering has to be done in userspace since the kernel does not support filtering on IFLA_INFO_SLAVE_KIND. Functionality introduced in this patch is not fully complete since it does not allow to match on type and slave type at the same time, but it doesn't prevent implementing a dedicated slave_type match, either. Signed-off-by: Phil Sutter --- ip/ipaddress.c | 52 +++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 8766530f..56f68eb2 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -61,6 +61,7 @@ static struct int group; int master; char *kind; + char *slave_kind; } filter; static int do_link; @@ -206,18 +207,27 @@ static void print_linkmode(FILE *f, struct rtattr *tb) fprintf(f, "mode %s ", link_modes[mode]); } -static char *parse_link_kind(struct rtattr *tb) +static char *parse_link_kind(struct rtattr *tb, bool slave) { struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + int attr = slave ? IFLA_INFO_SLAVE_KIND : IFLA_INFO_KIND; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb); - if (linkinfo[IFLA_INFO_KIND]) - return RTA_DATA(linkinfo[IFLA_INFO_KIND]); + if (linkinfo[attr]) + return RTA_DATA(linkinfo[attr]); return ""; } +static int match_link_kind(struct rtattr **tb, char *kind, bool slave) +{ + if (!tb[IFLA_LINKINFO]) + return -1; + + return strcmp(parse_link_kind(tb[IFLA_LINKINFO], slave), kind); +} + static void print_linktype(FILE *fp, struct rtattr *tb) { struct rtattr *linkinfo[IFLA_INFO_MAX+1]; @@ -680,16 +690,11 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, } else if (filter.master > 0) return -1; - if (filter.kind) { - if (tb[IFLA_LINKINFO]) { - char *kind = parse_link_kind(tb[IFLA_LINKINFO]); + if (filter.kind && match_link_kind(tb, filter.kind, 0)) + return -1; - if (strcmp(kind, filter.kind)) - return -1; - } else { - return -1; - } - } + if (filter.slave_kind && match_link_kind(tb, filter.slave_kind, 1)) + return -1; if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); @@ -781,16 +786,11 @@ int print_linkinfo(const struct sockaddr_nl *who, } else if (filter.master > 0) return -1; - if (filter.kind) { - if (tb[IFLA_LINKINFO]) { - char *kind = parse_link_kind(tb[IFLA_LINKINFO]); + if (filter.kind && match_link_kind(tb, filter.kind, 0)) + return -1; - if (strcmp(kind, filter.kind)) - return -1; - } else { - return -1; - } - } + if (filter.slave_kind && match_link_kind(tb, filter.slave_kind, 1)) + return -1; if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); @@ -1621,8 +1621,16 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) invarg("Device does not exist\n", *argv); filter.master = ifindex; } else if (strcmp(*argv, "type") == 0) { + int soff; + NEXT_ARG(); - filter.kind = *argv; + soff = strlen(*argv) - strlen("_slave"); + if (!strcmp(*argv + soff, "_slave")) { + (*argv)[soff] = '\0'; + filter.slave_kind = *argv; + } else { + filter.kind = *argv; + } } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); From 577cfe0b677e509c2614c5b67fd9a25a6e432af2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 15:07:17 +0200 Subject: [PATCH 6/9] ip-address: Align type list in help and man page This adds missing entries on both sides until they are identical. Signed-off-by: Phil Sutter --- ip/ipaddress.c | 6 +++--- man/man8/ip-address.8.in | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 56f68eb2..d4d64950 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -95,9 +95,9 @@ static void usage(void) fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"); fprintf(stderr, "LFT := forever | SECONDS\n"); fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); - fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); - fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); - fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n"); + fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); + fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon | can |\n"); + fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | hsr}\n"); exit(-1); } diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 8d34adb3..3cbe4181 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -98,7 +98,9 @@ ip-address \- protocol address management .ti -8 .IR TYPE " := [ " .BR bridge " | " +.BR bridge_slave " |" .BR bond " | " +.BR bond_slave " |" .BR can " | " .BR dummy " | " .BR hsr " | " @@ -118,6 +120,7 @@ ip-address \- protocol address management .BR ip6gre " |" .BR ip6gretap " |" .BR vti " |" +.BR vrf " |" .BR nlmon " |" .BR ipvlan " |" .BR lowpan " |" From eecc006952d6f3992b632974d0f04f995d2a176e Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Wed, 29 Jun 2016 02:27:14 +0300 Subject: [PATCH 7/9] ip route: timeout for routes has to be set in seconds Currently a timeout is multiplied by HZ in user-space and then it multiplied by HZ in kernel-space. $ ./ip/ip r add 2002::0/64 dev veth1 expires 10 $ ./ip/ip -6 r 2002::/64 dev veth1 metric 1024 linkdown expires 996sec pref medium Cc: Xin Long Cc: Hangbin Liu Cc: Stephen Hemminger Fixes: 68eede250500 ("route: allow routes to be configured with expire values") Signed-off-by: Andrew Vagin --- ip/iproute.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 8224d7ff..7c0f5a4f 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -839,7 +839,6 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) int table_ok = 0; int raw = 0; int type_ok = 0; - static int hz; memset(&req, 0, sizeof(req)); @@ -923,9 +922,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) NEXT_ARG(); if (get_u32(&expires, *argv, 0)) invarg("\"expires\" value is invalid\n", *argv); - if (!hz) - hz = get_user_hz(); - addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires*hz); + addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires); } else if (matches(*argv, "metric") == 0 || matches(*argv, "priority") == 0 || strcmp(*argv, "preference") == 0) { From 400b5404af35f58f501780663693886d37c2061e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 29 Jun 2016 15:26:10 -0400 Subject: [PATCH 8/9] bridge: man: fix BPUD typo s/BPUD/BPDU/ in guard description. Signed-off-by: Vivien Didelot --- man/man8/bridge.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index ac42118e..a30ed0b3 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -256,7 +256,7 @@ STP BPDUs. .TP .BR "guard on " or " guard off " -Controls whether STP BPUDs will be processed by the bridge port. By default, +Controls whether STP BPDUs will be processed by the bridge port. By default, the flag is turned off allowed BPDU processing. Turning this flag on will cause the port to stop processing STP BPDUs. From 3aa8f8cb7af952bd09efb7ec6d4f3f0507ada16a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 29 Jun 2016 15:26:29 -0400 Subject: [PATCH 9/9] bridge: man: fix STP LISTENING description Correct the unclear and poorly conjugated STP LISTENING documentation. Signed-off-by: Vivien Didelot --- man/man8/bridge.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index a30ed0b3..ef4f83ee 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -235,7 +235,7 @@ error. .B 1 - STP LISTENING state. Only valid if STP is enabled on the bridge. In this -state the port for list for STP BPDUs and drop all other traffic. +state the port listens for STP BPDUs and drops all other traffic frames. .sp .B 2