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) ...@@ -1614,9 +1614,13 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
int ret = 0; int ret = 0;
long timeo; 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; 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))); mptcp_lock_sock(sk, __mptcp_wmem_reserve(sk, min_t(size_t, 1 << 20, len)));
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
...@@ -1739,36 +1743,41 @@ static void mptcp_wait_data(struct sock *sk, long *timeo) ...@@ -1739,36 +1743,41 @@ static void mptcp_wait_data(struct sock *sk, long *timeo)
static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
struct msghdr *msg, struct msghdr *msg,
size_t len) size_t len, int flags)
{ {
struct sk_buff *skb; struct sk_buff *skb, *tmp;
int copied = 0; 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 offset = MPTCP_SKB_CB(skb)->offset;
u32 data_len = skb->len - offset; u32 data_len = skb->len - offset;
u32 count = min_t(size_t, len - copied, data_len); u32 count = min_t(size_t, len - copied, data_len);
int err; int err;
err = skb_copy_datagram_msg(skb, offset, msg, count); if (!(flags & MSG_TRUNC)) {
if (unlikely(err < 0)) { err = skb_copy_datagram_msg(skb, offset, msg, count);
if (!copied) if (unlikely(err < 0)) {
return err; if (!copied)
break; return err;
break;
}
} }
copied += count; copied += count;
if (count < data_len) { if (count < data_len) {
MPTCP_SKB_CB(skb)->offset += count; if (!(flags & MSG_PEEK))
MPTCP_SKB_CB(skb)->offset += count;
break; break;
} }
/* we will bulk release the skb memory later */ if (!(flags & MSG_PEEK)) {
skb->destructor = NULL; /* we will bulk release the skb memory later */
msk->rmem_released += skb->truesize; skb->destructor = NULL;
__skb_unlink(skb, &msk->receive_queue); msk->rmem_released += skb->truesize;
__kfree_skb(skb); __skb_unlink(skb, &msk->receive_queue);
__kfree_skb(skb);
}
if (copied >= len) if (copied >= len)
break; break;
...@@ -1945,8 +1954,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -1945,8 +1954,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int target; int target;
long timeo; long timeo;
if (msg->msg_flags & ~(MSG_WAITALL | MSG_DONTWAIT)) /* MSG_ERRQUEUE is really a no-op till we support IP_RECVERR */
return -EOPNOTSUPP; if (unlikely(flags & MSG_ERRQUEUE))
return inet_recv_error(sk, msg, len, addr_len);
mptcp_lock_sock(sk, __mptcp_splice_receive_queue(sk)); mptcp_lock_sock(sk, __mptcp_splice_receive_queue(sk));
if (unlikely(sk->sk_state == TCP_LISTEN)) { if (unlikely(sk->sk_state == TCP_LISTEN)) {
...@@ -1962,7 +1972,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -1962,7 +1972,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
while (copied < len) { while (copied < len) {
int bytes_read; 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 (unlikely(bytes_read < 0)) {
if (!copied) if (!copied)
copied = bytes_read; copied = bytes_read;
...@@ -2046,7 +2056,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -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", pr_debug("msk=%p data_ready=%d rx queue empty=%d copied=%d",
msk, test_bit(MPTCP_DATA_READY, &msk->flags), msk, test_bit(MPTCP_DATA_READY, &msk->flags),
skb_queue_empty_lockless(&sk->sk_receive_queue), copied); 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); release_sock(sk);
return copied; return copied;
......
...@@ -45,7 +45,14 @@ enum cfg_mode { ...@@ -45,7 +45,14 @@ enum cfg_mode {
CFG_MODE_SENDFILE, 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_mode cfg_mode = CFG_MODE_POLL;
static enum cfg_peek cfg_peek = CFG_NONE_PEEK;
static const char *cfg_host; static const char *cfg_host;
static const char *cfg_port = "12000"; static const char *cfg_port = "12000";
static int cfg_sock_proto = IPPROTO_MPTCP; static int cfg_sock_proto = IPPROTO_MPTCP;
...@@ -73,6 +80,8 @@ static void die_usage(void) ...@@ -73,6 +80,8 @@ static void die_usage(void)
fprintf(stderr, "\t-M mark -- set socket packet mark\n"); fprintf(stderr, "\t-M mark -- set socket packet mark\n");
fprintf(stderr, "\t-u -- check mptcp ulp\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-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); exit(1);
} }
...@@ -331,6 +340,8 @@ static size_t do_write(const int fd, char *buf, const size_t len) ...@@ -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) 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(); size_t cap = rand();
cap &= 0xffff; cap &= 0xffff;
...@@ -340,7 +351,17 @@ static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) ...@@ -340,7 +351,17 @@ static ssize_t do_rnd_read(const int fd, char *buf, const size_t len)
else if (cap > len) else if (cap > len)
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) static void set_nonblock(int fd)
...@@ -819,6 +840,26 @@ int parse_mode(const char *mode) ...@@ -819,6 +840,26 @@ int parse_mode(const char *mode)
return 0; 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) static int parse_int(const char *size)
{ {
unsigned long s; unsigned long s;
...@@ -846,7 +887,7 @@ static void parse_opts(int argc, char **argv) ...@@ -846,7 +887,7 @@ static void parse_opts(int argc, char **argv)
{ {
int c; 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) { switch (c) {
case 'j': case 'j':
cfg_join = true; cfg_join = true;
...@@ -899,6 +940,9 @@ static void parse_opts(int argc, char **argv) ...@@ -899,6 +940,9 @@ static void parse_opts(int argc, char **argv)
case 'M': case 'M':
cfg_mark = strtol(optarg, NULL, 0); cfg_mark = strtol(optarg, NULL, 0);
break; break;
case 'P':
cfg_peek = parse_peek(optarg);
break;
} }
} }
......
...@@ -375,7 +375,7 @@ do_transfer() ...@@ -375,7 +375,7 @@ do_transfer()
local srv_proto="$4" local srv_proto="$4"
local connect_addr="$5" local connect_addr="$5"
local local_addr="$6" local local_addr="$6"
local extra_args="" local extra_args="$7"
local port local port
port=$((10000+$TEST_COUNT)) port=$((10000+$TEST_COUNT))
...@@ -394,9 +394,9 @@ do_transfer() ...@@ -394,9 +394,9 @@ do_transfer()
fi fi
if [ -n "$extra_args" ] && $options_log; then if [ -n "$extra_args" ] && $options_log; then
options_log=false
echo "INFO: extra options: $extra_args" echo "INFO: extra options: $extra_args"
fi fi
options_log=false
:> "$cout" :> "$cout"
:> "$sout" :> "$sout"
...@@ -589,6 +589,7 @@ run_tests_lo() ...@@ -589,6 +589,7 @@ run_tests_lo()
local connector_ns="$2" local connector_ns="$2"
local connect_addr="$3" local connect_addr="$3"
local loopback="$4" local loopback="$4"
local extra_args="$5"
local lret=0 local lret=0
# skip if test programs are running inside same netns for subsequent runs. # skip if test programs are running inside same netns for subsequent runs.
...@@ -608,7 +609,8 @@ run_tests_lo() ...@@ -608,7 +609,8 @@ run_tests_lo()
local_addr="0.0.0.0" local_addr="0.0.0.0"
fi 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=$? lret=$?
if [ $lret -ne 0 ]; then if [ $lret -ne 0 ]; then
ret=$lret ret=$lret
...@@ -622,14 +624,16 @@ run_tests_lo() ...@@ -622,14 +624,16 @@ run_tests_lo()
fi fi
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=$? lret=$?
if [ $lret -ne 0 ]; then if [ $lret -ne 0 ]; then
ret=$lret ret=$lret
return 1 return 1
fi 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=$? lret=$?
if [ $lret -ne 0 ]; then if [ $lret -ne 0 ]; then
ret=$lret ret=$lret
...@@ -637,7 +641,8 @@ run_tests_lo() ...@@ -637,7 +641,8 @@ run_tests_lo()
fi fi
if [ $do_tcp -gt 1 ] ;then 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=$? lret=$?
if [ $lret -ne 0 ]; then if [ $lret -ne 0 ]; then
ret=$lret ret=$lret
...@@ -653,6 +658,15 @@ run_tests() ...@@ -653,6 +658,15 @@ run_tests()
run_tests_lo $1 $2 $3 0 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 "$cin" "client"
make_file "$sin" "server" make_file "$sin" "server"
...@@ -732,6 +746,9 @@ for sender in $ns1 $ns2 $ns3 $ns4;do ...@@ -732,6 +746,9 @@ for sender in $ns1 $ns2 $ns3 $ns4;do
run_tests "$ns4" $sender dead:beef:3::1 run_tests "$ns4" $sender dead:beef:3::1
done done
run_tests_peekmode "saveWithPeek"
run_tests_peekmode "saveAfterPeek"
time_end=$(date +%s) time_end=$(date +%s)
time_run=$((time_end-time_start)) 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