Commit bd6e229f authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-msg-flags'

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: default avatarDavid S. Miller <davem@davemloft.net>
parents b1ce98c7 df8aee6d
......@@ -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);
......@@ -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;
......@@ -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)) {
......@@ -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;
......@@ -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;
......
......@@ -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;
......@@ -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);
}
......@@ -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;
......@@ -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)
......@@ -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;
......@@ -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;
......@@ -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;
}
}
......
......@@ -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))
......@@ -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"
......@@ -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.
......@@ -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
......@@ -622,14 +624,16 @@ 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
......@@ -637,7 +641,8 @@ run_tests_lo()
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
......@@ -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"
......@@ -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))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment