Skip to content

Commit aa1fbd9

Browse files
Florian Westphaldavem330
authored andcommitted
mptcp: sockopt: add TCP_CONGESTION and TCP_INFO
TCP_CONGESTION is set for all subflows. The mptcp socket gains icsk_ca_ops too so it can be used to keep the authoritative state that should be set on new/future subflows. TCP_INFO will return first subflow only. The out-of-tree kernel has a MPTCP_INFO getsockopt, this could be added later on. Acked-by: Paolo Abeni <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a03c99b commit aa1fbd9

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

net/mptcp/protocol.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,9 @@ static int __mptcp_init_sock(struct sock *sk)
23992399
/* re-use the csk retrans timer for MPTCP-level retrans */
24002400
timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer, 0);
24012401
timer_setup(&sk->sk_timer, mptcp_timeout_timer, 0);
2402+
2403+
tcp_assign_congestion_control(sk);
2404+
24022405
return 0;
24032406
}
24042407

@@ -2592,6 +2595,8 @@ static void __mptcp_destroy_sock(struct sock *sk)
25922595
WARN_ON_ONCE(msk->rmem_released);
25932596
sk_stream_kill_queues(sk);
25942597
xfrm_sk_free_policy(sk);
2598+
2599+
tcp_cleanup_congestion_control(sk);
25952600
sk_refcnt_debug_release(sk);
25962601
mptcp_dispose_initial_subflow(msk);
25972602
sock_put(sk);

net/mptcp/sockopt.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,62 @@ static bool mptcp_supported_sockopt(int level, int optname)
510510
return false;
511511
}
512512

513+
static int mptcp_setsockopt_sol_tcp_congestion(struct mptcp_sock *msk, sockptr_t optval,
514+
unsigned int optlen)
515+
{
516+
struct mptcp_subflow_context *subflow;
517+
struct sock *sk = (struct sock *)msk;
518+
char name[TCP_CA_NAME_MAX];
519+
bool cap_net_admin;
520+
int ret;
521+
522+
if (optlen < 1)
523+
return -EINVAL;
524+
525+
ret = strncpy_from_sockptr(name, optval,
526+
min_t(long, TCP_CA_NAME_MAX - 1, optlen));
527+
if (ret < 0)
528+
return -EFAULT;
529+
530+
name[ret] = 0;
531+
532+
cap_net_admin = ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN);
533+
534+
ret = 0;
535+
lock_sock(sk);
536+
sockopt_seq_inc(msk);
537+
mptcp_for_each_subflow(msk, subflow) {
538+
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
539+
int err;
540+
541+
lock_sock(ssk);
542+
err = tcp_set_congestion_control(ssk, name, true, cap_net_admin);
543+
if (err < 0 && ret == 0)
544+
ret = err;
545+
subflow->setsockopt_seq = msk->setsockopt_seq;
546+
release_sock(ssk);
547+
}
548+
549+
if (ret == 0)
550+
tcp_set_congestion_control(sk, name, false, cap_net_admin);
551+
552+
release_sock(sk);
553+
return ret;
554+
}
555+
556+
static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
557+
sockptr_t optval, unsigned int optlen)
558+
{
559+
switch (optname) {
560+
case TCP_ULP:
561+
return -EOPNOTSUPP;
562+
case TCP_CONGESTION:
563+
return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen);
564+
}
565+
566+
return -EOPNOTSUPP;
567+
}
568+
513569
int mptcp_setsockopt(struct sock *sk, int level, int optname,
514570
sockptr_t optval, unsigned int optlen)
515571
{
@@ -539,6 +595,49 @@ int mptcp_setsockopt(struct sock *sk, int level, int optname,
539595
if (level == SOL_IPV6)
540596
return mptcp_setsockopt_v6(msk, optname, optval, optlen);
541597

598+
if (level == SOL_TCP)
599+
return mptcp_setsockopt_sol_tcp(msk, optname, optval, optlen);
600+
601+
return -EOPNOTSUPP;
602+
}
603+
604+
static int mptcp_getsockopt_first_sf_only(struct mptcp_sock *msk, int level, int optname,
605+
char __user *optval, int __user *optlen)
606+
{
607+
struct sock *sk = (struct sock *)msk;
608+
struct socket *ssock;
609+
int ret = -EINVAL;
610+
struct sock *ssk;
611+
612+
lock_sock(sk);
613+
ssk = msk->first;
614+
if (ssk) {
615+
ret = tcp_getsockopt(ssk, level, optname, optval, optlen);
616+
goto out;
617+
}
618+
619+
ssock = __mptcp_nmpc_socket(msk);
620+
if (!ssock)
621+
goto out;
622+
623+
ret = tcp_getsockopt(ssock->sk, level, optname, optval, optlen);
624+
625+
out:
626+
release_sock(sk);
627+
return ret;
628+
}
629+
630+
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
631+
char __user *optval, int __user *optlen)
632+
{
633+
switch (optname) {
634+
case TCP_ULP:
635+
case TCP_CONGESTION:
636+
case TCP_INFO:
637+
case TCP_CC_INFO:
638+
return mptcp_getsockopt_first_sf_only(msk, SOL_TCP, optname,
639+
optval, optlen);
640+
}
542641
return -EOPNOTSUPP;
543642
}
544643

@@ -562,6 +661,8 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname,
562661
if (ssk)
563662
return tcp_getsockopt(ssk, level, optname, optval, option);
564663

664+
if (level == SOL_TCP)
665+
return mptcp_getsockopt_sol_tcp(msk, optname, optval, option);
565666
return -EOPNOTSUPP;
566667
}
567668

0 commit comments

Comments
 (0)