Merge branch 'iproute2-master' into next

Conflicts:
	misc/ss.c

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2019-02-22 18:50:39 -08:00
commit 9f78e995a8
18 changed files with 221 additions and 62 deletions

View File

@ -346,8 +346,7 @@ static int fdb_show(int argc, char **argv)
if (rth.flags & RTNL_HANDLE_F_STRICT_CHK) if (rth.flags & RTNL_HANDLE_F_STRICT_CHK)
rc = rtnl_neighdump_req(&rth, PF_BRIDGE, fdb_dump_filter); rc = rtnl_neighdump_req(&rth, PF_BRIDGE, fdb_dump_filter);
else else
rc = rtnl_linkdump_req_filter_fn(&rth, PF_BRIDGE, rc = rtnl_fdb_linkdump_req_filter_fn(&rth, fdb_linkdump_filter);
fdb_linkdump_filter);
if (rc < 0) { if (rc < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
exit(1); exit(1);

View File

@ -4525,7 +4525,8 @@ static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]); size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]); counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
resource_valid = !!nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]; resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
ctx->resources;
if (resource_valid) { if (resource_valid) {
table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]); table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
table->resource_valid = true; table->resource_valid = true;
@ -4641,12 +4642,9 @@ static int cmd_dpipe_table_show(struct dl *dl)
dl_opts_put(nlh, dl); dl_opts_put(nlh, dl);
err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
&resource_ctx); &resource_ctx);
if (err) { if (!err)
pr_err("error get resources %s\n", strerror(resource_ctx.err)); dpipe_ctx.resources = resource_ctx.resources;
goto err_resource_dump;
}
dpipe_ctx.resources = resource_ctx.resources;
flags = NLM_F_REQUEST | NLM_F_ACK; flags = NLM_F_REQUEST | NLM_F_ACK;
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags); nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
dl_opts_put(nlh, dl); dl_opts_put(nlh, dl);
@ -4659,8 +4657,6 @@ static int cmd_dpipe_table_show(struct dl *dl)
dpipe_ctx_fini(&dpipe_ctx); dpipe_ctx_fini(&dpipe_ctx);
return 0; return 0;
err_resource_dump:
resource_ctx_fini(&resource_ctx);
err_resource_ctx_init: err_resource_ctx_init:
err_headers_get: err_headers_get:
dpipe_ctx_fini(&dpipe_ctx); dpipe_ctx_fini(&dpipe_ctx);

View File

@ -81,6 +81,9 @@ int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam, int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam,
req_filter_fn_t fn) req_filter_fn_t fn)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
req_filter_fn_t filter_fn)
__attribute__((warn_unused_result));
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask) int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
__attribute__((warn_unused_result)); __attribute__((warn_unused_result));
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,

View File

@ -137,15 +137,21 @@ enum {
INET_DIAG_TCLASS, INET_DIAG_TCLASS,
INET_DIAG_SKMEMINFO, INET_DIAG_SKMEMINFO,
INET_DIAG_SHUTDOWN, INET_DIAG_SHUTDOWN,
INET_DIAG_DCTCPINFO,
INET_DIAG_PROTOCOL, /* response attribute only */ /*
* Next extenstions cannot be requested in struct inet_diag_req_v2:
* its field idiag_ext has only 8 bits.
*/
INET_DIAG_DCTCPINFO, /* request as INET_DIAG_VEGASINFO */
INET_DIAG_PROTOCOL, /* response attribute only */
INET_DIAG_SKV6ONLY, INET_DIAG_SKV6ONLY,
INET_DIAG_LOCALS, INET_DIAG_LOCALS,
INET_DIAG_PEERS, INET_DIAG_PEERS,
INET_DIAG_PAD, INET_DIAG_PAD,
INET_DIAG_MARK, INET_DIAG_MARK, /* only with CAP_NET_ADMIN */
INET_DIAG_BBRINFO, INET_DIAG_BBRINFO, /* request as INET_DIAG_VEGASINFO */
INET_DIAG_CLASS_ID, INET_DIAG_CLASS_ID, /* request as INET_DIAG_TCLASS */
INET_DIAG_MD5SIG, INET_DIAG_MD5SIG,
__INET_DIAG_MAX, __INET_DIAG_MAX,
}; };

View File

@ -547,7 +547,7 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
return; return;
} }
parse_rtattr_nested(vf, IFLA_VF_MAX, vfstats); parse_rtattr_nested(vf, IFLA_VF_STATS_MAX, vfstats);
if (is_json_context()) { if (is_json_context()) {
open_json_object("stats"); open_json_object("stats");

View File

@ -98,7 +98,7 @@ void iplink_usage(void)
" [ trust { on | off} ] ]\n" " [ trust { on | off} ] ]\n"
" [ node_guid { eui64 } ]\n" " [ node_guid { eui64 } ]\n"
" [ port_guid { eui64 } ]\n" " [ port_guid { eui64 } ]\n"
" [ xdp { off |\n" " [ { xdp | xdpgeneric | xdpdrv | xdpoffload } { off |\n"
" object FILE [ section NAME ] [ verbose ] |\n" " object FILE [ section NAME ] [ verbose ] |\n"
" pinned FILE } ]\n" " pinned FILE } ]\n"
" [ master DEVICE ][ vrf NAME ]\n" " [ master DEVICE ][ vrf NAME ]\n"

View File

@ -1932,6 +1932,7 @@ static int iproute_get(int argc, char **argv)
int fib_match = 0; int fib_match = 0;
int from_ok = 0; int from_ok = 0;
unsigned int mark = 0; unsigned int mark = 0;
bool address_found = false;
iproute_reset_filter(0); iproute_reset_filter(0);
filter.cloned = 2; filter.cloned = 2;
@ -2037,11 +2038,12 @@ static int iproute_get(int argc, char **argv)
addattr_l(&req.n, sizeof(req), addattr_l(&req.n, sizeof(req),
RTA_DST, &addr.data, addr.bytelen); RTA_DST, &addr.data, addr.bytelen);
req.r.rtm_dst_len = addr.bitlen; req.r.rtm_dst_len = addr.bitlen;
address_found = true;
} }
argc--; argv++; argc--; argv++;
} }
if (req.r.rtm_dst_len == 0) { if (!address_found) {
fprintf(stderr, "need at least a destination address\n"); fprintf(stderr, "need at least a destination address\n");
return -1; return -1;
} }

View File

@ -31,7 +31,7 @@
#include <linux/seg6_iptunnel.h> #include <linux/seg6_iptunnel.h>
#include <linux/seg6_hmac.h> #include <linux/seg6_hmac.h>
#include <linux/seg6_local.h> #include <linux/seg6_local.h>
#include <net/if.h> #include <linux/if_tunnel.h>
static const char *format_encap_type(int type) static const char *format_encap_type(int type)
{ {
@ -294,6 +294,7 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
static void print_encap_ip(FILE *fp, struct rtattr *encap) static void print_encap_ip(FILE *fp, struct rtattr *encap)
{ {
struct rtattr *tb[LWTUNNEL_IP_MAX+1]; struct rtattr *tb[LWTUNNEL_IP_MAX+1];
__u16 flags;
parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap); parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
@ -318,6 +319,16 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
if (tb[LWTUNNEL_IP_TOS]) if (tb[LWTUNNEL_IP_TOS])
print_uint(PRINT_ANY, "tos", print_uint(PRINT_ANY, "tos",
"tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS])); "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
if (tb[LWTUNNEL_IP_FLAGS]) {
flags = rta_getattr_u16(tb[LWTUNNEL_IP_FLAGS]);
if (flags & TUNNEL_KEY)
print_bool(PRINT_ANY, "key", "key ", true);
if (flags & TUNNEL_CSUM)
print_bool(PRINT_ANY, "csum", "csum ", true);
if (flags & TUNNEL_SEQ)
print_bool(PRINT_ANY, "seq", "seq ", true);
}
} }
static void print_encap_ila(FILE *fp, struct rtattr *encap) static void print_encap_ila(FILE *fp, struct rtattr *encap)
@ -354,6 +365,7 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap)
static void print_encap_ip6(FILE *fp, struct rtattr *encap) static void print_encap_ip6(FILE *fp, struct rtattr *encap)
{ {
struct rtattr *tb[LWTUNNEL_IP6_MAX+1]; struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
__u16 flags;
parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap); parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
@ -379,6 +391,16 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
if (tb[LWTUNNEL_IP6_TC]) if (tb[LWTUNNEL_IP6_TC])
print_uint(PRINT_ANY, "tc", print_uint(PRINT_ANY, "tc",
"tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC])); "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
if (tb[LWTUNNEL_IP6_FLAGS]) {
flags = rta_getattr_u16(tb[LWTUNNEL_IP6_FLAGS]);
if (flags & TUNNEL_KEY)
print_bool(PRINT_ANY, "key", "key ", true);
if (flags & TUNNEL_CSUM)
print_bool(PRINT_ANY, "csum", "csum ", true);
if (flags & TUNNEL_SEQ)
print_bool(PRINT_ANY, "seq", "seq ", true);
}
} }
static void print_encap_bpf(FILE *fp, struct rtattr *encap) static void print_encap_bpf(FILE *fp, struct rtattr *encap)
@ -777,9 +799,11 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
int *argcp, char ***argvp) int *argcp, char ***argvp)
{ {
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0; int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
int key_ok = 0, csum_ok = 0, seq_ok = 0;
char **argv = *argvp; char **argv = *argvp;
int argc = *argcp; int argc = *argcp;
int ret = 0; int ret = 0;
__u16 flags = 0;
while (argc > 0) { while (argc > 0) {
if (strcmp(*argv, "id") == 0) { if (strcmp(*argv, "id") == 0) {
@ -827,6 +851,18 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
if (get_u8(&ttl, *argv, 0)) if (get_u8(&ttl, *argv, 0))
invarg("\"ttl\" value is invalid\n", *argv); invarg("\"ttl\" value is invalid\n", *argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl); ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);
flags |= TUNNEL_KEY;
} else if (strcmp(*argv, "csum") == 0) {
if (csum_ok++)
duparg2("csum", *argv);
flags |= TUNNEL_CSUM;
} else if (strcmp(*argv, "seq") == 0) {
if (seq_ok++)
duparg2("seq", *argv);
flags |= TUNNEL_SEQ;
} else { } else {
break; break;
} }
@ -835,6 +871,9 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
argc--; argv++; argc--; argv++;
} }
if (flags)
ret = rta_addattr16(rta, len, LWTUNNEL_IP_FLAGS, flags);
/* argv is currently the first unparsed argument, /* argv is currently the first unparsed argument,
* but the lwt_parse_encap() caller will move to the next, * but the lwt_parse_encap() caller will move to the next,
* so step back * so step back
@ -927,9 +966,11 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
int *argcp, char ***argvp) int *argcp, char ***argvp)
{ {
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0; int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
int key_ok = 0, csum_ok = 0, seq_ok = 0;
char **argv = *argvp; char **argv = *argvp;
int argc = *argcp; int argc = *argcp;
int ret = 0; int ret = 0;
__u16 flags = 0;
while (argc > 0) { while (argc > 0) {
if (strcmp(*argv, "id") == 0) { if (strcmp(*argv, "id") == 0) {
@ -979,6 +1020,18 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
*argv); *argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
hoplimit); hoplimit);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);
flags |= TUNNEL_KEY;
} else if (strcmp(*argv, "csum") == 0) {
if (csum_ok++)
duparg2("csum", *argv);
flags |= TUNNEL_CSUM;
} else if (strcmp(*argv, "seq") == 0) {
if (seq_ok++)
duparg2("seq", *argv);
flags |= TUNNEL_SEQ;
} else { } else {
break; break;
} }
@ -987,6 +1040,9 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
argc--; argv++; argc--; argv++;
} }
if (flags)
ret = rta_addattr16(rta, len, LWTUNNEL_IP6_FLAGS, flags);
/* argv is currently the first unparsed argument, /* argv is currently the first unparsed argument,
* but the lwt_parse_encap() caller will move to the next, * but the lwt_parse_encap() caller will move to the next,
* so step back * so step back

View File

@ -459,7 +459,7 @@ int print_rule(struct nlmsghdr *n, void *arg)
} else if (frh->action == FR_ACT_NOP) { } else if (frh->action == FR_ACT_NOP) {
print_null(PRINT_ANY, "nop", "nop", NULL); print_null(PRINT_ANY, "nop", "nop", NULL);
} else if (frh->action != FR_ACT_TO_TBL) { } else if (frh->action != FR_ACT_TO_TBL) {
print_string(PRINT_ANY, "to_tbl", "%s", print_string(PRINT_ANY, "action", "%s",
rtnl_rtntype_n2a(frh->action, b1, sizeof(b1))); rtnl_rtntype_n2a(frh->action, b1, sizeof(b1)));
} }

View File

@ -2203,12 +2203,16 @@ static int bpf_btf_prep_type_data(struct bpf_elf_ctx *ctx)
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
type_cur += var_len * sizeof(struct btf_enum); type_cur += var_len * sizeof(struct btf_enum);
break; break;
case BTF_KIND_FUNC_PROTO:
type_cur += var_len * sizeof(struct btf_param);
break;
case BTF_KIND_TYPEDEF: case BTF_KIND_TYPEDEF:
case BTF_KIND_PTR: case BTF_KIND_PTR:
case BTF_KIND_FWD: case BTF_KIND_FWD:
case BTF_KIND_VOLATILE: case BTF_KIND_VOLATILE:
case BTF_KIND_CONST: case BTF_KIND_CONST:
case BTF_KIND_RESTRICT: case BTF_KIND_RESTRICT:
case BTF_KIND_FUNC:
break; break;
default: default:
fprintf(stderr, "Object has unknown BTF type: %u!\n", kind); fprintf(stderr, "Object has unknown BTF type: %u!\n", kind);

View File

@ -476,7 +476,7 @@ int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family, int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
req_filter_fn_t filter_fn) req_filter_fn_t filter_fn)
{ {
if (family == AF_UNSPEC) { if (family == AF_UNSPEC || family == AF_PACKET) {
struct { struct {
struct nlmsghdr nlh; struct nlmsghdr nlh;
struct ifinfomsg ifm; struct ifinfomsg ifm;
@ -503,6 +503,29 @@ int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
return __rtnl_linkdump_req(rth, family); return __rtnl_linkdump_req(rth, family);
} }
int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
req_filter_fn_t filter_fn)
{
struct {
struct nlmsghdr nlh;
struct ifinfomsg ifm;
char buf[128];
} req = {
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.nlh.nlmsg_type = RTM_GETNEIGH,
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
.ifm.ifi_family = PF_BRIDGE,
};
int err;
err = filter_fn(&req.nlh, sizeof(req));
if (err)
return err;
return send(rth->fd, &req, sizeof(req), 0);
}
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask) int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
{ {
struct { struct {
@ -695,6 +718,8 @@ static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
if (len < 0) if (len < 0)
return len; return len;
if (len < 32768)
len = 32768;
buf = malloc(len); buf = malloc(len);
if (!buf) { if (!buf) {
fprintf(stderr, "malloc error: not enough buffer\n"); fprintf(stderr, "malloc error: not enough buffer\n");

View File

@ -344,7 +344,7 @@ Controls whether a given port will sync MAC addresses learned on device port to
bridge FDB. bridge FDB.
.TP .TP
.BR "flooding on " or " flooding off " .BR "flood on " or " flood off "
Controls whether a given port will flood unicast traffic for which there is no FDB entry. By default this flag is on. Controls whether a given port will flood unicast traffic for which there is no FDB entry. By default this flag is on.
.TP .TP
@ -361,7 +361,7 @@ switch.
.TP .TP
.BR "mcast_flood on " or " mcast_flood off " .BR "mcast_flood on " or " mcast_flood off "
Controls whether a given port will be flooded with multicast traffic for which there is no MDB entry. By default this flag is on. Controls whether a given port will flood multicast traffic for which there is no MDB entry. By default this flag is on.
.TP .TP
.BR "neigh_suppress on " or " neigh_suppress off " .BR "neigh_suppress on " or " neigh_suppress off "

View File

@ -2183,7 +2183,7 @@ queries.
option above. option above.
.BR mcast_flood " { " on " | " off " }" .BR mcast_flood " { " on " | " off " }"
- controls whether a given port will be flooded with multicast traffic for which there is no MDB entry. - controls whether a given port will flood multicast traffic for which there is no MDB entry.
.BI group_fwd_mask " MASK " .BI group_fwd_mask " MASK "
- set the group forward mask. This is the bitmask that is applied to decide whether to forward incoming frames destined to link-local addresses, ie addresses of the form 01:80:C2:00:00:0X (defaults to 0, ie the bridge does not forward any link-local frames coming on this port). - set the group forward mask. This is the bitmask that is applied to decide whether to forward incoming frames destined to link-local addresses, ie addresses of the form 01:80:C2:00:00:0X (defaults to 0, ie the bridge does not forward any link-local frames coming on this port).

View File

@ -737,7 +737,8 @@ is a set of encapsulation attributes specific to the
.B tos .B tos
.IR TOS " ] [" .IR TOS " ] ["
.B ttl .B ttl
.IR TTL " ]" .IR TTL " ] [ "
.BR key " ] [" csum " ] [ " seq " ] "
.in -2 .in -2
.sp .sp

View File

@ -244,6 +244,23 @@ the pacing rate and max pacing rate
a helper variable for TCP internal auto tuning socket receive buffer a helper variable for TCP internal auto tuning socket receive buffer
.RE .RE
.TP .TP
.B \-\-tos
Show ToS and priority information. Below fields may appear:
.RS
.P
.TP
.B tos
IPv4 Type-of-Service byte
.P
.TP
.B tclass
IPv6 Traffic Class byte
.P
.TP
.B class_id
Class id set by net_cls cgroup. If class is zero this shows priority set by SO_PRIORITY.
.RE
.TP
.B \-K, \-\-kill .B \-K, \-\-kill
Attempts to forcibly close sockets. This option displays sockets that are Attempts to forcibly close sockets. This option displays sockets that are
successfully closed and silently skips sockets that the kernel does not support successfully closed and silently skips sockets that the kernel does not support

105
misc/ss.c
View File

@ -52,8 +52,17 @@
#include <linux/tipc_netlink.h> #include <linux/tipc_netlink.h>
#include <linux/tipc_sockets_diag.h> #include <linux/tipc_sockets_diag.h>
/* AF_VSOCK/PF_VSOCK is only provided since glibc 2.18 */
#ifndef PF_VSOCK
#define PF_VSOCK 40
#endif
#ifndef AF_VSOCK
#define AF_VSOCK PF_VSOCK
#endif
#define MAGIC_SEQ 123456 #define MAGIC_SEQ 123456
#define BUF_CHUNK (1024 * 1024) #define BUF_CHUNK (1024 * 1024) /* Buffer chunk allocation size */
#define BUF_CHUNKS_MAX 5 /* Maximum number of allocated buffer chunks */
#define LEN_ALIGN(x) (((x) + 1) & ~1) #define LEN_ALIGN(x) (((x) + 1) & ~1)
#define DIAG_REQUEST(_req, _r) \ #define DIAG_REQUEST(_req, _r) \
@ -111,6 +120,7 @@ static int show_header = 1;
static int follow_events; static int follow_events;
static int sctp_ino; static int sctp_ino;
static int show_tipcinfo; static int show_tipcinfo;
static int show_tos;
enum col_id { enum col_id {
COL_NETID, COL_NETID,
@ -176,6 +186,7 @@ static struct {
struct buf_token *cur; /* Position of current token in chunk */ struct buf_token *cur; /* Position of current token in chunk */
struct buf_chunk *head; /* First chunk */ struct buf_chunk *head; /* First chunk */
struct buf_chunk *tail; /* Current chunk */ struct buf_chunk *tail; /* Current chunk */
int chunks; /* Number of allocated chunks */
} buffer; } buffer;
static const char *TCP_PROTO = "tcp"; static const char *TCP_PROTO = "tcp";
@ -946,6 +957,8 @@ static struct buf_chunk *buf_chunk_new(void)
new->end = buffer.cur->data; new->end = buffer.cur->data;
buffer.chunks++;
return new; return new;
} }
@ -1090,33 +1103,6 @@ static int field_is_last(struct column *f)
return f - columns == COL_MAX - 1; return f - columns == COL_MAX - 1;
} }
static void field_next(void)
{
field_flush(current_field);
if (field_is_last(current_field))
current_field = columns;
else
current_field++;
}
/* Walk through fields and flush them until we reach the desired one */
static void field_set(enum col_id id)
{
while (id != current_field - columns)
field_next();
}
/* Print header for all non-empty columns */
static void print_header(void)
{
while (!field_is_last(current_field)) {
if (!current_field->disabled)
out("%s", current_field->header);
field_next();
}
}
/* Get the next available token in the buffer starting from the current token */ /* Get the next available token in the buffer starting from the current token */
static struct buf_token *buf_token_next(struct buf_token *cur) static struct buf_token *buf_token_next(struct buf_token *cur)
{ {
@ -1142,6 +1128,7 @@ static void buf_free_all(void)
free(tmp); free(tmp);
} }
buffer.head = NULL; buffer.head = NULL;
buffer.chunks = 0;
} }
/* Get current screen width, default to 80 columns if TIOCGWINSZ fails */ /* Get current screen width, default to 80 columns if TIOCGWINSZ fails */
@ -1304,6 +1291,40 @@ static void render(void)
current_field = columns; current_field = columns;
} }
/* Move to next field, and render buffer if we reached the maximum number of
* chunks, at the last field in a line.
*/
static void field_next(void)
{
if (field_is_last(current_field) && buffer.chunks >= BUF_CHUNKS_MAX) {
render();
return;
}
field_flush(current_field);
if (field_is_last(current_field))
current_field = columns;
else
current_field++;
}
/* Walk through fields and flush them until we reach the desired one */
static void field_set(enum col_id id)
{
while (id != current_field - columns)
field_next();
}
/* Print header for all non-empty columns */
static void print_header(void)
{
while (!field_is_last(current_field)) {
if (!current_field->disabled)
out("%s", current_field->header);
field_next();
}
}
static void sock_state_print(struct sockstat *s) static void sock_state_print(struct sockstat *s)
{ {
const char *sock_name; const char *sock_name;
@ -3022,6 +3043,15 @@ static int inet_show_sock(struct nlmsghdr *nlh,
} }
} }
if (show_tos) {
if (tb[INET_DIAG_TOS])
out(" tos:%#x", rta_getattr_u8(tb[INET_DIAG_TOS]));
if (tb[INET_DIAG_TCLASS])
out(" tclass:%#x", rta_getattr_u8(tb[INET_DIAG_TCLASS]));
if (tb[INET_DIAG_CLASS_ID])
out(" class_id:%#x", rta_getattr_u32(tb[INET_DIAG_CLASS_ID]));
}
if (show_mem || (show_tcpinfo && s->type != IPPROTO_UDP)) { if (show_mem || (show_tcpinfo && s->type != IPPROTO_UDP)) {
out("\n\t"); out("\n\t");
if (s->type == IPPROTO_SCTP) if (s->type == IPPROTO_SCTP)
@ -3072,6 +3102,11 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f)
req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1)); req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
} }
if (show_tos) {
req.r.idiag_ext |= (1<<(INET_DIAG_TOS-1));
req.r.idiag_ext |= (1<<(INET_DIAG_TCLASS-1));
}
iov[0] = (struct iovec){ iov[0] = (struct iovec){
.iov_base = &req, .iov_base = &req,
.iov_len = sizeof(req) .iov_len = sizeof(req)
@ -3132,6 +3167,11 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1)); req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
} }
if (show_tos) {
req.r.idiag_ext |= (1<<(INET_DIAG_TOS-1));
req.r.idiag_ext |= (1<<(INET_DIAG_TCLASS-1));
}
iov[0] = (struct iovec){ iov[0] = (struct iovec){
.iov_base = &req, .iov_base = &req,
.iov_len = sizeof(req) .iov_len = sizeof(req)
@ -4814,6 +4854,7 @@ static void _usage(FILE *dest)
" -i, --info show internal TCP information\n" " -i, --info show internal TCP information\n"
" --tipcinfo show internal tipc socket information\n" " --tipcinfo show internal tipc socket information\n"
" -s, --summary show socket usage summary\n" " -s, --summary show socket usage summary\n"
" --tos show tos and priority information\n"
" -b, --bpf show bpf filter socket information\n" " -b, --bpf show bpf filter socket information\n"
" -E, --events continually display sockets as they are destroyed\n" " -E, --events continually display sockets as they are destroyed\n"
" -Z, --context display process SELinux security contexts\n" " -Z, --context display process SELinux security contexts\n"
@ -4918,8 +4959,10 @@ static int scan_state(const char *state)
#define OPT_TIPCSOCK 257 #define OPT_TIPCSOCK 257
#define OPT_TIPCINFO 258 #define OPT_TIPCINFO 258
#define OPT_TOS 259
/* Values of 'x' are already used so a non-character is used */ /* Values of 'x' are already used so a non-character is used */
#define OPT_XDPSOCK 259 #define OPT_XDPSOCK 260
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "numeric", 0, 0, 'n' }, { "numeric", 0, 0, 'n' },
@ -4956,6 +4999,7 @@ static const struct option long_opts[] = {
{ "contexts", 0, 0, 'z' }, { "contexts", 0, 0, 'z' },
{ "net", 1, 0, 'N' }, { "net", 1, 0, 'N' },
{ "tipcinfo", 0, 0, OPT_TIPCINFO}, { "tipcinfo", 0, 0, OPT_TIPCINFO},
{ "tos", 0, 0, OPT_TOS },
{ "kill", 0, 0, 'K' }, { "kill", 0, 0, 'K' },
{ "no-header", 0, 0, 'H' }, { "no-header", 0, 0, 'H' },
{ "xdp", 0, 0, OPT_XDPSOCK}, { "xdp", 0, 0, OPT_XDPSOCK},
@ -5139,6 +5183,9 @@ int main(int argc, char *argv[])
case OPT_TIPCINFO: case OPT_TIPCINFO:
show_tipcinfo = 1; show_tipcinfo = 1;
break; break;
case OPT_TOS:
show_tos = 1;
break;
case 'K': case 'K':
current_filter.kill = 1; current_filter.kill = 1;
break; break;

View File

@ -14,6 +14,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <net/if.h> #include <net/if.h>
#include <linux/limits.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/ip.h> #include <linux/ip.h>

View File

@ -190,12 +190,13 @@ static const struct rate_suffix {
{ NULL } { NULL }
}; };
static int parse_percent_rate(char *rate, const char *str, const char *dev) static int parse_percent_rate(char *rate, size_t len,
const char *str, const char *dev)
{ {
long dev_mbit; long dev_mbit;
int ret; int ret;
double perc, rate_mbit; double perc, rate_bit;
char *str_perc; char *str_perc = NULL;
if (!dev[0]) { if (!dev[0]) {
fprintf(stderr, "No device specified; specify device to rate limit by percentage\n"); fprintf(stderr, "No device specified; specify device to rate limit by percentage\n");
@ -219,10 +220,10 @@ static int parse_percent_rate(char *rate, const char *str, const char *dev)
return -1; return -1;
} }
rate_mbit = perc * dev_mbit; rate_bit = perc * dev_mbit * 1000 * 1000;
ret = snprintf(rate, 20, "%lf", rate_mbit); ret = snprintf(rate, len, "%lf", rate_bit);
if (ret <= 0 || ret >= 20) { if (ret <= 0 || ret >= len) {
fprintf(stderr, "Unable to parse calculated rate\n"); fprintf(stderr, "Unable to parse calculated rate\n");
return -1; return -1;
} }
@ -230,6 +231,7 @@ static int parse_percent_rate(char *rate, const char *str, const char *dev)
return 0; return 0;
malf: malf:
free(str_perc);
fprintf(stderr, "Specified rate value could not be read or is malformed\n"); fprintf(stderr, "Specified rate value could not be read or is malformed\n");
return -1; return -1;
} }
@ -238,7 +240,7 @@ int get_percent_rate(unsigned int *rate, const char *str, const char *dev)
{ {
char r_str[20]; char r_str[20];
if (parse_percent_rate(r_str, str, dev)) if (parse_percent_rate(r_str, sizeof(r_str), str, dev))
return -1; return -1;
return get_rate(rate, r_str); return get_rate(rate, r_str);
@ -248,7 +250,7 @@ int get_percent_rate64(__u64 *rate, const char *str, const char *dev)
{ {
char r_str[20]; char r_str[20];
if (parse_percent_rate(r_str, str, dev)) if (parse_percent_rate(r_str, sizeof(r_str), str, dev))
return -1; return -1;
return get_rate64(rate, r_str); return get_rate64(rate, r_str);