Skip to content

Commit

Permalink
Merge branch 'mptcp-msg-flags'
Browse files Browse the repository at this point in the history
Mat Martineau says:

====================
mptcp: Compatibility with common msg flags

These patches from the MPTCP tree handle some of the msg flags that are
typically used with TCP, to make it easier to adapt userspace programs
for use with MPTCP.

Patches 1, 2, and 4 add support for MSG_ERRQUEUE (no-op for now),
MSG_TRUNC, and MSG_PEEK on the receive side.

Patch 3 ignores unsupported msg flags for send and receive.

Patch 5 adds a selftest for MSG_PEEK.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 23, 2021
2 parents b1ce98c + df8aee6 commit bd6e229
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 27 deletions.
49 changes: 30 additions & 19 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1614,9 +1614,13 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
int ret = 0;
long timeo;

if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL))
/* we don't support FASTOPEN yet */
if (msg->msg_flags & MSG_FASTOPEN)
return -EOPNOTSUPP;

/* silently ignore everything else */
msg->msg_flags &= MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL;

mptcp_lock_sock(sk, __mptcp_wmem_reserve(sk, min_t(size_t, 1 << 20, len)));

timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
Expand Down Expand Up @@ -1739,36 +1743,41 @@ static void mptcp_wait_data(struct sock *sk, long *timeo)

static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
struct msghdr *msg,
size_t len)
size_t len, int flags)
{
struct sk_buff *skb;
struct sk_buff *skb, *tmp;
int copied = 0;

while ((skb = skb_peek(&msk->receive_queue)) != NULL) {
skb_queue_walk_safe(&msk->receive_queue, skb, tmp) {
u32 offset = MPTCP_SKB_CB(skb)->offset;
u32 data_len = skb->len - offset;
u32 count = min_t(size_t, len - copied, data_len);
int err;

err = skb_copy_datagram_msg(skb, offset, msg, count);
if (unlikely(err < 0)) {
if (!copied)
return err;
break;
if (!(flags & MSG_TRUNC)) {
err = skb_copy_datagram_msg(skb, offset, msg, count);
if (unlikely(err < 0)) {
if (!copied)
return err;
break;
}
}

copied += count;

if (count < data_len) {
MPTCP_SKB_CB(skb)->offset += count;
if (!(flags & MSG_PEEK))
MPTCP_SKB_CB(skb)->offset += count;
break;
}

/* we will bulk release the skb memory later */
skb->destructor = NULL;
msk->rmem_released += skb->truesize;
__skb_unlink(skb, &msk->receive_queue);
__kfree_skb(skb);
if (!(flags & MSG_PEEK)) {
/* we will bulk release the skb memory later */
skb->destructor = NULL;
msk->rmem_released += skb->truesize;
__skb_unlink(skb, &msk->receive_queue);
__kfree_skb(skb);
}

if (copied >= len)
break;
Expand Down Expand Up @@ -1945,8 +1954,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int target;
long timeo;

if (msg->msg_flags & ~(MSG_WAITALL | MSG_DONTWAIT))
return -EOPNOTSUPP;
/* MSG_ERRQUEUE is really a no-op till we support IP_RECVERR */
if (unlikely(flags & MSG_ERRQUEUE))
return inet_recv_error(sk, msg, len, addr_len);

mptcp_lock_sock(sk, __mptcp_splice_receive_queue(sk));
if (unlikely(sk->sk_state == TCP_LISTEN)) {
Expand All @@ -1962,7 +1972,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
while (copied < len) {
int bytes_read;

bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied);
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags);
if (unlikely(bytes_read < 0)) {
if (!copied)
copied = bytes_read;
Expand Down Expand Up @@ -2046,7 +2056,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
pr_debug("msk=%p data_ready=%d rx queue empty=%d copied=%d",
msk, test_bit(MPTCP_DATA_READY, &msk->flags),
skb_queue_empty_lockless(&sk->sk_receive_queue), copied);
mptcp_rcv_space_adjust(msk, copied);
if (!(flags & MSG_PEEK))
mptcp_rcv_space_adjust(msk, copied);

release_sock(sk);
return copied;
Expand Down
48 changes: 46 additions & 2 deletions tools/testing/selftests/net/mptcp/mptcp_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ enum cfg_mode {
CFG_MODE_SENDFILE,
};

enum cfg_peek {
CFG_NONE_PEEK,
CFG_WITH_PEEK,
CFG_AFTER_PEEK,
};

static enum cfg_mode cfg_mode = CFG_MODE_POLL;
static enum cfg_peek cfg_peek = CFG_NONE_PEEK;
static const char *cfg_host;
static const char *cfg_port = "12000";
static int cfg_sock_proto = IPPROTO_MPTCP;
Expand Down Expand Up @@ -73,6 +80,8 @@ static void die_usage(void)
fprintf(stderr, "\t-M mark -- set socket packet mark\n");
fprintf(stderr, "\t-u -- check mptcp ulp\n");
fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n");
fprintf(stderr,
"\t-P [saveWithPeek|saveAfterPeek] -- save data with/after MSG_PEEK form tcp socket\n");
exit(1);
}

Expand Down Expand Up @@ -331,6 +340,8 @@ static size_t do_write(const int fd, char *buf, const size_t len)

static ssize_t do_rnd_read(const int fd, char *buf, const size_t len)
{
int ret = 0;
char tmp[16384];
size_t cap = rand();

cap &= 0xffff;
Expand All @@ -340,7 +351,17 @@ static ssize_t do_rnd_read(const int fd, char *buf, const size_t len)
else if (cap > len)
cap = len;

return read(fd, buf, cap);
if (cfg_peek == CFG_WITH_PEEK) {
ret = recv(fd, buf, cap, MSG_PEEK);
ret = (ret < 0) ? ret : read(fd, tmp, ret);
} else if (cfg_peek == CFG_AFTER_PEEK) {
ret = recv(fd, buf, cap, MSG_PEEK);
ret = (ret < 0) ? ret : read(fd, buf, cap);
} else {
ret = read(fd, buf, cap);
}

return ret;
}

static void set_nonblock(int fd)
Expand Down Expand Up @@ -819,6 +840,26 @@ int parse_mode(const char *mode)
return 0;
}

int parse_peek(const char *mode)
{
if (!strcasecmp(mode, "saveWithPeek"))
return CFG_WITH_PEEK;
if (!strcasecmp(mode, "saveAfterPeek"))
return CFG_AFTER_PEEK;

fprintf(stderr, "Unknown: %s\n", mode);
fprintf(stderr, "Supported MSG_PEEK mode are:\n");
fprintf(stderr,
"\t\t\"saveWithPeek\" - recv data with flags 'MSG_PEEK' and save the peek data into file\n");
fprintf(stderr,
"\t\t\"saveAfterPeek\" - read and save data into file after recv with flags 'MSG_PEEK'\n");

die_usage();

/* silence compiler warning */
return 0;
}

static int parse_int(const char *size)
{
unsigned long s;
Expand Down Expand Up @@ -846,7 +887,7 @@ static void parse_opts(int argc, char **argv)
{
int c;

while ((c = getopt(argc, argv, "6jr:lp:s:hut:m:S:R:w:M:")) != -1) {
while ((c = getopt(argc, argv, "6jr:lp:s:hut:m:S:R:w:M:P:")) != -1) {
switch (c) {
case 'j':
cfg_join = true;
Expand Down Expand Up @@ -899,6 +940,9 @@ static void parse_opts(int argc, char **argv)
case 'M':
cfg_mark = strtol(optarg, NULL, 0);
break;
case 'P':
cfg_peek = parse_peek(optarg);
break;
}
}

Expand Down
29 changes: 23 additions & 6 deletions tools/testing/selftests/net/mptcp/mptcp_connect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ do_transfer()
local srv_proto="$4"
local connect_addr="$5"
local local_addr="$6"
local extra_args=""
local extra_args="$7"

local port
port=$((10000+$TEST_COUNT))
Expand All @@ -394,9 +394,9 @@ do_transfer()
fi

if [ -n "$extra_args" ] && $options_log; then
options_log=false
echo "INFO: extra options: $extra_args"
fi
options_log=false

:> "$cout"
:> "$sout"
Expand Down Expand Up @@ -589,6 +589,7 @@ run_tests_lo()
local connector_ns="$2"
local connect_addr="$3"
local loopback="$4"
local extra_args="$5"
local lret=0

# skip if test programs are running inside same netns for subsequent runs.
Expand All @@ -608,7 +609,8 @@ run_tests_lo()
local_addr="0.0.0.0"
fi

do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} ${local_addr}
do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \
${connect_addr} ${local_addr} "${extra_args}"
lret=$?
if [ $lret -ne 0 ]; then
ret=$lret
Expand All @@ -622,22 +624,25 @@ run_tests_lo()
fi
fi

do_transfer ${listener_ns} ${connector_ns} MPTCP TCP ${connect_addr} ${local_addr}
do_transfer ${listener_ns} ${connector_ns} MPTCP TCP \
${connect_addr} ${local_addr} "${extra_args}"
lret=$?
if [ $lret -ne 0 ]; then
ret=$lret
return 1
fi

do_transfer ${listener_ns} ${connector_ns} TCP MPTCP ${connect_addr} ${local_addr}
do_transfer ${listener_ns} ${connector_ns} TCP MPTCP \
${connect_addr} ${local_addr} "${extra_args}"
lret=$?
if [ $lret -ne 0 ]; then
ret=$lret
return 1
fi

if [ $do_tcp -gt 1 ] ;then
do_transfer ${listener_ns} ${connector_ns} TCP TCP ${connect_addr} ${local_addr}
do_transfer ${listener_ns} ${connector_ns} TCP TCP \
${connect_addr} ${local_addr} "${extra_args}"
lret=$?
if [ $lret -ne 0 ]; then
ret=$lret
Expand All @@ -653,6 +658,15 @@ run_tests()
run_tests_lo $1 $2 $3 0
}

run_tests_peekmode()
{
local peekmode="$1"

echo "INFO: with peek mode: ${peekmode}"
run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-P ${peekmode}"
run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-P ${peekmode}"
}

make_file "$cin" "client"
make_file "$sin" "server"

Expand Down Expand Up @@ -732,6 +746,9 @@ for sender in $ns1 $ns2 $ns3 $ns4;do
run_tests "$ns4" $sender dead:beef:3::1
done

run_tests_peekmode "saveWithPeek"
run_tests_peekmode "saveAfterPeek"

time_end=$(date +%s)
time_run=$((time_end-time_start))

Expand Down

0 comments on commit bd6e229

Please sign in to comment.