Commit 5cbd886c authored by Florian Westphal's avatar Florian Westphal Committed by Jakub Kicinski
Browse files

selftests: mptcp: add TCP_INQ support



Do checks on the returned inq counter.

Fail on:
1. Huge value (> 1 kbyte, test case files are 1 kb)
2. last hint larger than returned bytes when read was short
3. erronenous indication of EOF.

3) happens when a hint of X bytes reads X-1 on next call
   but next recvmsg returns more data (instead of EOF).

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2c9e7765
Loading
Loading
Loading
Loading
+59 −1
Original line number Diff line number Diff line
@@ -73,12 +73,20 @@ static uint32_t cfg_mark;
struct cfg_cmsg_types {
	unsigned int cmsg_enabled:1;
	unsigned int timestampns:1;
	unsigned int tcp_inq:1;
};

struct cfg_sockopt_types {
	unsigned int transparent:1;
};

struct tcp_inq_state {
	unsigned int last;
	bool expect_eof;
};

static struct tcp_inq_state tcp_inq;

static struct cfg_cmsg_types cfg_cmsg_types;
static struct cfg_sockopt_types cfg_sockopt_types;

@@ -389,7 +397,9 @@ static size_t do_write(const int fd, char *buf, const size_t len)
static void process_cmsg(struct msghdr *msgh)
{
	struct __kernel_timespec ts;
	bool inq_found = false;
	bool ts_found = false;
	unsigned int inq = 0;
	struct cmsghdr *cmsg;

	for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
@@ -398,12 +408,27 @@ static void process_cmsg(struct msghdr *msgh)
			ts_found = true;
			continue;
		}
		if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) {
			memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq));
			inq_found = true;
			continue;
		}

	}

	if (cfg_cmsg_types.timestampns) {
		if (!ts_found)
			xerror("TIMESTAMPNS not present\n");
	}

	if (cfg_cmsg_types.tcp_inq) {
		if (!inq_found)
			xerror("TCP_INQ not present\n");

		if (inq > 1024)
			xerror("tcp_inq %u is larger than one kbyte\n", inq);
		tcp_inq.last = inq;
	}
}

static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len)
@@ -420,11 +445,24 @@ static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len)
		.msg_controllen = sizeof(msg_buf),
	};
	int flags = 0;
	unsigned int last_hint = tcp_inq.last;
	int ret = recvmsg(fd, &msg, flags);

	if (ret <= 0)
	if (ret <= 0) {
		if (ret == 0 && tcp_inq.expect_eof)
			return ret;

		if (ret == 0 && cfg_cmsg_types.tcp_inq)
			if (last_hint != 1 && last_hint != 0)
				xerror("EOF but last tcp_inq hint was %u\n", last_hint);

		return ret;
	}

	if (tcp_inq.expect_eof)
		xerror("expected EOF, last_hint %u, now %u\n",
		       last_hint, tcp_inq.last);

	if (msg.msg_controllen && !cfg_cmsg_types.cmsg_enabled)
		xerror("got %lu bytes of cmsg data, expected 0\n",
		       (unsigned long)msg.msg_controllen);
@@ -435,6 +473,19 @@ static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len)
	if (msg.msg_controllen)
		process_cmsg(&msg);

	if (cfg_cmsg_types.tcp_inq) {
		if ((size_t)ret < len && last_hint > (unsigned int)ret) {
			if (ret + 1 != (int)last_hint) {
				int next = read(fd, msg_buf, sizeof(msg_buf));

				xerror("read %u of %u, last_hint was %u tcp_inq hint now %u next_read returned %d/%m\n",
				       ret, (unsigned int)len, last_hint, tcp_inq.last, next);
			} else {
				tcp_inq.expect_eof = true;
			}
		}
	}

	return ret;
}

@@ -944,6 +995,8 @@ static void apply_cmsg_types(int fd, const struct cfg_cmsg_types *cmsg)

	if (cmsg->timestampns)
		xsetsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, &on, sizeof(on));
	if (cmsg->tcp_inq)
		xsetsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on));
}

static void parse_cmsg_types(const char *type)
@@ -965,6 +1018,11 @@ static void parse_cmsg_types(const char *type)
		return;
	}

	if (strncmp(type, "TCPINQ", len) == 0) {
		cfg_cmsg_types.tcp_inq = 1;
		return;
	}

	fprintf(stderr, "Unrecognized cmsg option %s\n", type);
	exit(1);
}
+2 −2
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ do_transfer()

	timeout ${timeout_test} \
		ip netns exec ${listener_ns} \
			$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c TIMESTAMPNS \
			$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c TIMESTAMPNS,TCPINQ \
				${local_addr} < "$sin" > "$sout" &
	spid=$!

@@ -186,7 +186,7 @@ do_transfer()

	timeout ${timeout_test} \
		ip netns exec ${connector_ns} \
			$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMESTAMPNS \
			$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMESTAMPNS,TCPINQ \
				$connect_addr < "$cin" > "$cout" &

	cpid=$!