On Mon, Jun 25, 2018 at 10:06:46AM +0800, Xin Long wrote: > This feature is actually already supported by sk->sk_reuse which can be > set by socket level opt SO_REUSEADDR. But it's not working exactly as > RFC6458 demands in section 8.1.27, like: > > - This option only supports one-to-one style SCTP sockets > - This socket option must not be used after calling bind() > or sctp_bindx(). > > Besides, SCTP_REUSE_PORT sockopt should be provided for user's programs. > Otherwise, the programs with SCTP_REUSE_PORT from other systems will not > work in linux. > > To separate it from the socket level version, this patch adds 'reuse' in > sctp_sock and it works pretty much as sk->sk_reuse, but with some extra > setup limitations that are needed when it is being enabled. > > "It should be noted that the behavior of the socket-level socket option > to reuse ports and/or addresses for SCTP sockets is unspecified", so it > leaves SO_REUSEADDR as is for the compatibility. > > Note that the name SCTP_REUSE_PORT is kind of confusing, it is identical > to SO_REUSEADDR with some extra restriction, so here it uses 'reuse' in > sctp_sock instead of 'reuseport'. As for sk->sk_reuseport support for > SCTP, it will be added in another patch. To help changelog readers later, please update to something like: """\ Note that the name SCTP_REUSE_PORT is somewhat confusing, as its functionality is nearly identical to SO_REUSEADDR, but with some extra restrictions. Here it uses 'reuse' in sctp_sock instead of 'reuseport'. As for sk->sk_reuseport support for SCTP, it will be added in another patch. """ Makes sense, can you note the difference? > > Thanks to Neil to make this clear. > > v1->v2: > - add sctp_sk->reuse to separate it from the socket level version. > > Acked-by: Neil Horman <nhorman@xxxxxxxxxxxxx> > Signed-off-by: Xin Long <lucien.xin@xxxxxxxxx> > --- > include/net/sctp/structs.h | 1 + > include/uapi/linux/sctp.h | 1 + > net/sctp/socket.c | 62 ++++++++++++++++++++++++++++++++++++++++------ > 3 files changed, 57 insertions(+), 7 deletions(-) > > diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h > index e0f962d..701a517 100644 > --- a/include/net/sctp/structs.h > +++ b/include/net/sctp/structs.h > @@ -220,6 +220,7 @@ struct sctp_sock { > __u32 adaptation_ind; > __u32 pd_point; > __u16 nodelay:1, > + reuse:1, > disable_fragments:1, > v4mapped:1, > frag_interleave:1, > diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h > index b64d583..c02986a 100644 > --- a/include/uapi/linux/sctp.h > +++ b/include/uapi/linux/sctp.h > @@ -100,6 +100,7 @@ typedef __s32 sctp_assoc_t; > #define SCTP_RECVNXTINFO 33 > #define SCTP_DEFAULT_SNDINFO 34 > #define SCTP_AUTH_DEACTIVATE_KEY 35 > +#define SCTP_REUSE_PORT 36 > > /* Internal Socket Options. Some of the sctp library functions are > * implemented using these socket options. > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > index 0e91e83..bf11f9c 100644 > --- a/net/sctp/socket.c > +++ b/net/sctp/socket.c > @@ -4170,6 +4170,28 @@ static int sctp_setsockopt_interleaving_supported(struct sock *sk, > return retval; > } > > +static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, > + unsigned int optlen) > +{ > + int val; > + > + if (!sctp_style(sk, TCP)) > + return -EOPNOTSUPP; > + > + if (sctp_sk(sk)->ep->base.bind_addr.port) > + return -EFAULT; > + > + if (optlen < sizeof(int)) > + return -EINVAL; > + > + if (get_user(val, (int __user *)optval)) > + return -EFAULT; > + > + sctp_sk(sk)->reuse = !!val; > + > + return 0; > +} > + > /* API 6.2 setsockopt(), getsockopt() > * > * Applications use setsockopt() and getsockopt() to set or retrieve > @@ -4364,6 +4386,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, > retval = sctp_setsockopt_interleaving_supported(sk, optval, > optlen); > break; > + case SCTP_REUSE_PORT: > + retval = sctp_setsockopt_reuse_port(sk, optval, optlen); > + break; > default: > retval = -ENOPROTOOPT; > break; > @@ -7197,6 +7222,26 @@ static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len, > return retval; > } > > +static int sctp_getsockopt_reuse_port(struct sock *sk, int len, > + char __user *optval, > + int __user *optlen) > +{ > + int val; > + > + if (len < sizeof(int)) > + return -EINVAL; > + > + len = sizeof(int); > + val = sctp_sk(sk)->reuse; > + if (put_user(len, optlen)) > + return -EFAULT; > + > + if (copy_to_user(optval, &val, len)) > + return -EFAULT; > + > + return 0; > +} > + > static int sctp_getsockopt(struct sock *sk, int level, int optname, > char __user *optval, int __user *optlen) > { > @@ -7392,6 +7437,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, > retval = sctp_getsockopt_interleaving_supported(sk, len, optval, > optlen); > break; > + case SCTP_REUSE_PORT: > + retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); > + break; > default: > retval = -ENOPROTOOPT; > break; > @@ -7429,6 +7477,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( > > static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) > { > + bool reuse = (sk->sk_reuse || sctp_sk(sk)->reuse); > struct sctp_bind_hashbucket *head; /* hash list */ > struct sctp_bind_bucket *pp; > unsigned short snum; > @@ -7501,13 +7550,11 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) > * used by other socket (pp->owner not empty); that other > * socket is going to be sk2. > */ > - int reuse = sk->sk_reuse; > struct sock *sk2; > > pr_debug("%s: found a possible match\n", __func__); > > - if (pp->fastreuse && sk->sk_reuse && > - sk->sk_state != SCTP_SS_LISTENING) > + if (pp->fastreuse && reuse && sk->sk_state != SCTP_SS_LISTENING) > goto success; > > /* Run through the list of sockets bound to the port > @@ -7525,7 +7572,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) > ep2 = sctp_sk(sk2)->ep; > > if (sk == sk2 || > - (reuse && sk2->sk_reuse && > + (reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) && > sk2->sk_state != SCTP_SS_LISTENING)) > continue; > > @@ -7549,12 +7596,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) > * SO_REUSEADDR on this socket -sk-). > */ > if (hlist_empty(&pp->owner)) { > - if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING) > + if (reuse && sk->sk_state != SCTP_SS_LISTENING) > pp->fastreuse = 1; > else > pp->fastreuse = 0; > } else if (pp->fastreuse && > - (!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING)) > + (!reuse || sk->sk_state == SCTP_SS_LISTENING)) > pp->fastreuse = 0; > > /* We are set, so fill up all the data in the hash table > @@ -7685,7 +7732,7 @@ int sctp_inet_listen(struct socket *sock, int backlog) > err = 0; > sctp_unhash_endpoint(ep); > sk->sk_state = SCTP_SS_CLOSED; > - if (sk->sk_reuse) > + if (sk->sk_reuse || sctp_sk(sk)->reuse) > sctp_sk(sk)->bind_hash->fastreuse = 1; > goto out; > } > @@ -8550,6 +8597,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, > newsk->sk_no_check_tx = sk->sk_no_check_tx; > newsk->sk_no_check_rx = sk->sk_no_check_rx; > newsk->sk_reuse = sk->sk_reuse; > + sctp_sk(newsk)->reuse = sp->reuse; > > newsk->sk_shutdown = sk->sk_shutdown; > newsk->sk_destruct = sctp_destruct_sock; > -- > 2.1.0 > -- To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html