Skip to content

Commit b0e9a2f

Browse files
lxindavem330
authored andcommitted
sctp: add support for SCTP_REUSE_PORT sockopt
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 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. Thanks to Neil to make this clear. v1->v2: - add sctp_sk->reuse to separate it from the socket level version. v2->v3: - improve changelog according to Marcelo's suggestion. Acked-by: Neil Horman <[email protected]> Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 23c94d6 commit b0e9a2f

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

include/net/sctp/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ struct sctp_sock {
220220
__u32 adaptation_ind;
221221
__u32 pd_point;
222222
__u16 nodelay:1,
223+
reuse:1,
223224
disable_fragments:1,
224225
v4mapped:1,
225226
frag_interleave:1,

include/uapi/linux/sctp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ typedef __s32 sctp_assoc_t;
100100
#define SCTP_RECVNXTINFO 33
101101
#define SCTP_DEFAULT_SNDINFO 34
102102
#define SCTP_AUTH_DEACTIVATE_KEY 35
103+
#define SCTP_REUSE_PORT 36
103104

104105
/* Internal Socket Options. Some of the sctp library functions are
105106
* implemented using these socket options.

net/sctp/socket.c

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4170,6 +4170,28 @@ static int sctp_setsockopt_interleaving_supported(struct sock *sk,
41704170
return retval;
41714171
}
41724172

4173+
static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval,
4174+
unsigned int optlen)
4175+
{
4176+
int val;
4177+
4178+
if (!sctp_style(sk, TCP))
4179+
return -EOPNOTSUPP;
4180+
4181+
if (sctp_sk(sk)->ep->base.bind_addr.port)
4182+
return -EFAULT;
4183+
4184+
if (optlen < sizeof(int))
4185+
return -EINVAL;
4186+
4187+
if (get_user(val, (int __user *)optval))
4188+
return -EFAULT;
4189+
4190+
sctp_sk(sk)->reuse = !!val;
4191+
4192+
return 0;
4193+
}
4194+
41734195
/* API 6.2 setsockopt(), getsockopt()
41744196
*
41754197
* Applications use setsockopt() and getsockopt() to set or retrieve
@@ -4364,6 +4386,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
43644386
retval = sctp_setsockopt_interleaving_supported(sk, optval,
43654387
optlen);
43664388
break;
4389+
case SCTP_REUSE_PORT:
4390+
retval = sctp_setsockopt_reuse_port(sk, optval, optlen);
4391+
break;
43674392
default:
43684393
retval = -ENOPROTOOPT;
43694394
break;
@@ -7197,6 +7222,26 @@ static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len,
71977222
return retval;
71987223
}
71997224

7225+
static int sctp_getsockopt_reuse_port(struct sock *sk, int len,
7226+
char __user *optval,
7227+
int __user *optlen)
7228+
{
7229+
int val;
7230+
7231+
if (len < sizeof(int))
7232+
return -EINVAL;
7233+
7234+
len = sizeof(int);
7235+
val = sctp_sk(sk)->reuse;
7236+
if (put_user(len, optlen))
7237+
return -EFAULT;
7238+
7239+
if (copy_to_user(optval, &val, len))
7240+
return -EFAULT;
7241+
7242+
return 0;
7243+
}
7244+
72007245
static int sctp_getsockopt(struct sock *sk, int level, int optname,
72017246
char __user *optval, int __user *optlen)
72027247
{
@@ -7392,6 +7437,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
73927437
retval = sctp_getsockopt_interleaving_supported(sk, len, optval,
73937438
optlen);
73947439
break;
7440+
case SCTP_REUSE_PORT:
7441+
retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen);
7442+
break;
73957443
default:
73967444
retval = -ENOPROTOOPT;
73977445
break;
@@ -7429,6 +7477,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
74297477

74307478
static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
74317479
{
7480+
bool reuse = (sk->sk_reuse || sctp_sk(sk)->reuse);
74327481
struct sctp_bind_hashbucket *head; /* hash list */
74337482
struct sctp_bind_bucket *pp;
74347483
unsigned short snum;
@@ -7501,13 +7550,11 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
75017550
* used by other socket (pp->owner not empty); that other
75027551
* socket is going to be sk2.
75037552
*/
7504-
int reuse = sk->sk_reuse;
75057553
struct sock *sk2;
75067554

75077555
pr_debug("%s: found a possible match\n", __func__);
75087556

7509-
if (pp->fastreuse && sk->sk_reuse &&
7510-
sk->sk_state != SCTP_SS_LISTENING)
7557+
if (pp->fastreuse && reuse && sk->sk_state != SCTP_SS_LISTENING)
75117558
goto success;
75127559

75137560
/* 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)
75257572
ep2 = sctp_sk(sk2)->ep;
75267573

75277574
if (sk == sk2 ||
7528-
(reuse && sk2->sk_reuse &&
7575+
(reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) &&
75297576
sk2->sk_state != SCTP_SS_LISTENING))
75307577
continue;
75317578

@@ -7549,12 +7596,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
75497596
* SO_REUSEADDR on this socket -sk-).
75507597
*/
75517598
if (hlist_empty(&pp->owner)) {
7552-
if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING)
7599+
if (reuse && sk->sk_state != SCTP_SS_LISTENING)
75537600
pp->fastreuse = 1;
75547601
else
75557602
pp->fastreuse = 0;
75567603
} else if (pp->fastreuse &&
7557-
(!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING))
7604+
(!reuse || sk->sk_state == SCTP_SS_LISTENING))
75587605
pp->fastreuse = 0;
75597606

75607607
/* 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)
76857732
err = 0;
76867733
sctp_unhash_endpoint(ep);
76877734
sk->sk_state = SCTP_SS_CLOSED;
7688-
if (sk->sk_reuse)
7735+
if (sk->sk_reuse || sctp_sk(sk)->reuse)
76897736
sctp_sk(sk)->bind_hash->fastreuse = 1;
76907737
goto out;
76917738
}
@@ -8550,6 +8597,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
85508597
newsk->sk_no_check_tx = sk->sk_no_check_tx;
85518598
newsk->sk_no_check_rx = sk->sk_no_check_rx;
85528599
newsk->sk_reuse = sk->sk_reuse;
8600+
sctp_sk(newsk)->reuse = sp->reuse;
85538601

85548602
newsk->sk_shutdown = sk->sk_shutdown;
85558603
newsk->sk_destruct = sctp_destruct_sock;

0 commit comments

Comments
 (0)