#include "libnetlink.h"
#include "namespace.h"
#include "SNAPSHOT.h"
+#include "rt_names.h"
#include <linux/tcp.h>
#include <linux/sock_diag.h>
#include <linux/tipc_netlink.h>
#include <linux/tipc_sockets_diag.h>
#include <linux/tls.h>
+#include <linux/mptcp.h>
/* AF_VSOCK/PF_VSOCK is only provided since glibc 2.18 */
#ifndef PF_VSOCK
static int sctp_ino;
static int show_tipcinfo;
static int show_tos;
-int numeric;
int oneline;
enum col_id {
COL_RADDR,
COL_RSERV,
COL_EXT,
+ COL_PROC,
COL_MAX
};
{ ALIGN_LEFT, "Port", "", 0, 0, 0 },
{ ALIGN_RIGHT, "Peer Address:", " ", 0, 0, 0 },
{ ALIGN_LEFT, "Port", "", 0, 0, 0 },
+ { ALIGN_LEFT, "Process", "", 0, 0, 0 },
{ ALIGN_LEFT, "", "", 0, 0, 0 },
};
buffer.chunks = 0;
}
-/* Get current screen width, default to 80 columns if TIOCGWINSZ fails */
+/* Get current screen width, returns -1 if TIOCGWINSZ fails */
static int render_screen_width(void)
{
- int width = 80;
+ int width = -1;
if (isatty(STDOUT_FILENO)) {
struct winsize w;
*/
static void render_calc_width(void)
{
- int screen_width = render_screen_width();
+ int screen_width, first, len = 0, linecols = 0;
struct column *c, *eol = columns - 1;
- int first, len = 0, linecols = 0;
+ bool compact_output = false;
+
+ screen_width = render_screen_width();
+ if (screen_width == -1) {
+ screen_width = INT_MAX;
+ compact_output = true;
+ }
/* First pass: set width for each column to measured content length */
for (first = 1, c = columns; c - columns < COL_MAX; c++) {
first = 0;
}
+ if (compact_output) {
+ /* Compact output, skip extending columns. */
+ return;
+ }
+
/* Second pass: find out newlines and distribute available spacing */
for (c = columns; c - columns < COL_MAX; c++) {
int pad, spacing, rem, last;
token = buf_token_next(token);
}
+ /* Deal with final end-of-line when the last non-empty field printed
+ * is not the last field.
+ */
+ if (line_started)
+ printf("\n");
buf_free_all();
current_field = columns;
}
}
+static void mptcp_subflow_info(struct rtattr *tb[])
+{
+ u_int32_t flags = 0;
+
+ if (tb[MPTCP_SUBFLOW_ATTR_FLAGS]) {
+ char caps[32 + 1] = { 0 }, *cap = &caps[0];
+
+ flags = rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_FLAGS]);
+
+ if (flags & MPTCP_SUBFLOW_FLAG_MCAP_REM)
+ *cap++ = 'M';
+ if (flags & MPTCP_SUBFLOW_FLAG_MCAP_LOC)
+ *cap++ = 'm';
+ if (flags & MPTCP_SUBFLOW_FLAG_JOIN_REM)
+ *cap++ = 'J';
+ if (flags & MPTCP_SUBFLOW_FLAG_JOIN_LOC)
+ *cap++ = 'j';
+ if (flags & MPTCP_SUBFLOW_FLAG_BKUP_REM)
+ *cap++ = 'B';
+ if (flags & MPTCP_SUBFLOW_FLAG_BKUP_LOC)
+ *cap++ = 'b';
+ if (flags & MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED)
+ *cap++ = 'e';
+ if (flags & MPTCP_SUBFLOW_FLAG_CONNECTED)
+ *cap++ = 'c';
+ if (flags & MPTCP_SUBFLOW_FLAG_MAPVALID)
+ *cap++ = 'v';
+ if (flags)
+ out(" flags:%s", caps);
+ }
+ if (tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM] &&
+ tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC] &&
+ tb[MPTCP_SUBFLOW_ATTR_ID_REM] &&
+ tb[MPTCP_SUBFLOW_ATTR_ID_LOC])
+ out(" token:%04x(id:%hhu)/%04x(id:%hhu)",
+ rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM]),
+ rta_getattr_u8(tb[MPTCP_SUBFLOW_ATTR_ID_REM]),
+ rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC]),
+ rta_getattr_u8(tb[MPTCP_SUBFLOW_ATTR_ID_LOC]));
+ if (tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ])
+ out(" seq:%llx",
+ rta_getattr_u64(tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ]));
+ if (tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ])
+ out(" sfseq:%x",
+ rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ]));
+ if (tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET])
+ out(" ssnoff:%x",
+ rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET]));
+ if (tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN])
+ out(" maplen:%x",
+ rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN]));
+}
+
#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
tcp_tls_conf("rxconf", tlsinfo[TLS_INFO_RXCONF]);
tcp_tls_conf("txconf", tlsinfo[TLS_INFO_TXCONF]);
}
+ if (ulpinfo[INET_ULP_INFO_MPTCP]) {
+ struct rtattr *sfinfo[MPTCP_SUBFLOW_ATTR_MAX + 1] =
+ { 0 };
+
+ parse_rtattr_nested(sfinfo, MPTCP_SUBFLOW_ATTR_MAX,
+ ulpinfo[INET_ULP_INFO_MPTCP]);
+ mptcp_subflow_info(sfinfo);
+ }
}
}
}
while (1) {
- int status, err2;
+ int err2;
+ size_t status, nitems;
struct nlmsghdr *h = (struct nlmsghdr *)buf;
struct sockstat s = {};
status = fread(buf, 1, sizeof(*h), fp);
- if (status < 0) {
- perror("Reading header from $TCPDIAG_FILE");
- break;
- }
if (status != sizeof(*h)) {
- perror("Unexpected EOF reading $TCPDIAG_FILE");
+ if (ferror(fp))
+ perror("Reading header from $TCPDIAG_FILE");
+ if (feof(fp))
+ fprintf(stderr, "Unexpected EOF reading $TCPDIAG_FILE");
break;
}
- status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
+ nitems = NLMSG_ALIGN(h->nlmsg_len - sizeof(*h));
+ status = fread(h+1, 1, nitems, fp);
- if (status < 0) {
- perror("Reading $TCPDIAG_FILE");
- break;
- }
- if (status + sizeof(*h) < h->nlmsg_len) {
- perror("Unexpected EOF reading $TCPDIAG_FILE");
+ if (status != nitems) {
+ if (ferror(fp))
+ perror("Reading $TCPDIAG_FILE");
+ if (feof(fp))
+ fprintf(stderr, "Unexpected EOF reading $TCPDIAG_FILE");
break;
}