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/ip/ipaddress.c b/ip/ipaddress.c index 8766530f..d4d64950 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; @@ -94,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); } @@ -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(); 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) { diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index ac42118e..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 @@ -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. 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 " |" 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 02be7e74..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--; @@ -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); @@ -1273,11 +1279,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 +1299,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,16 +1319,25 @@ 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); *(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(); @@ -1402,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; @@ -2038,42 +2084,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 +2137,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]); @@ -2121,6 +2173,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; @@ -2156,18 +2209,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) { @@ -2188,6 +2244,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); @@ -2216,18 +2273,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) { @@ -2268,9 +2328,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 +2347,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 +2414,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 +2453,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; } 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");