mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25:19 +00:00
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 <nhorman@tuxdriver.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
23c94d63a7
commit
b0e9a2fe3f
3 changed files with 57 additions and 7 deletions
|
@ -220,6 +220,7 @@ struct sctp_sock {
|
||||||
__u32 adaptation_ind;
|
__u32 adaptation_ind;
|
||||||
__u32 pd_point;
|
__u32 pd_point;
|
||||||
__u16 nodelay:1,
|
__u16 nodelay:1,
|
||||||
|
reuse:1,
|
||||||
disable_fragments:1,
|
disable_fragments:1,
|
||||||
v4mapped:1,
|
v4mapped:1,
|
||||||
frag_interleave:1,
|
frag_interleave:1,
|
||||||
|
|
|
@ -100,6 +100,7 @@ typedef __s32 sctp_assoc_t;
|
||||||
#define SCTP_RECVNXTINFO 33
|
#define SCTP_RECVNXTINFO 33
|
||||||
#define SCTP_DEFAULT_SNDINFO 34
|
#define SCTP_DEFAULT_SNDINFO 34
|
||||||
#define SCTP_AUTH_DEACTIVATE_KEY 35
|
#define SCTP_AUTH_DEACTIVATE_KEY 35
|
||||||
|
#define SCTP_REUSE_PORT 36
|
||||||
|
|
||||||
/* Internal Socket Options. Some of the sctp library functions are
|
/* Internal Socket Options. Some of the sctp library functions are
|
||||||
* implemented using these socket options.
|
* implemented using these socket options.
|
||||||
|
|
|
@ -4170,6 +4170,28 @@ out:
|
||||||
return retval;
|
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()
|
/* API 6.2 setsockopt(), getsockopt()
|
||||||
*
|
*
|
||||||
* Applications use setsockopt() and getsockopt() to set or retrieve
|
* 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,
|
retval = sctp_setsockopt_interleaving_supported(sk, optval,
|
||||||
optlen);
|
optlen);
|
||||||
break;
|
break;
|
||||||
|
case SCTP_REUSE_PORT:
|
||||||
|
retval = sctp_setsockopt_reuse_port(sk, optval, optlen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
retval = -ENOPROTOOPT;
|
retval = -ENOPROTOOPT;
|
||||||
break;
|
break;
|
||||||
|
@ -7197,6 +7222,26 @@ out:
|
||||||
return retval;
|
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,
|
static int sctp_getsockopt(struct sock *sk, int level, int optname,
|
||||||
char __user *optval, int __user *optlen)
|
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,
|
retval = sctp_getsockopt_interleaving_supported(sk, len, optval,
|
||||||
optlen);
|
optlen);
|
||||||
break;
|
break;
|
||||||
|
case SCTP_REUSE_PORT:
|
||||||
|
retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
retval = -ENOPROTOOPT;
|
retval = -ENOPROTOOPT;
|
||||||
break;
|
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)
|
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_hashbucket *head; /* hash list */
|
||||||
struct sctp_bind_bucket *pp;
|
struct sctp_bind_bucket *pp;
|
||||||
unsigned short snum;
|
unsigned short snum;
|
||||||
|
@ -7501,13 +7550,11 @@ pp_found:
|
||||||
* used by other socket (pp->owner not empty); that other
|
* used by other socket (pp->owner not empty); that other
|
||||||
* socket is going to be sk2.
|
* socket is going to be sk2.
|
||||||
*/
|
*/
|
||||||
int reuse = sk->sk_reuse;
|
|
||||||
struct sock *sk2;
|
struct sock *sk2;
|
||||||
|
|
||||||
pr_debug("%s: found a possible match\n", __func__);
|
pr_debug("%s: found a possible match\n", __func__);
|
||||||
|
|
||||||
if (pp->fastreuse && sk->sk_reuse &&
|
if (pp->fastreuse && reuse && sk->sk_state != SCTP_SS_LISTENING)
|
||||||
sk->sk_state != SCTP_SS_LISTENING)
|
|
||||||
goto success;
|
goto success;
|
||||||
|
|
||||||
/* Run through the list of sockets bound to the port
|
/* Run through the list of sockets bound to the port
|
||||||
|
@ -7525,7 +7572,7 @@ pp_found:
|
||||||
ep2 = sctp_sk(sk2)->ep;
|
ep2 = sctp_sk(sk2)->ep;
|
||||||
|
|
||||||
if (sk == sk2 ||
|
if (sk == sk2 ||
|
||||||
(reuse && sk2->sk_reuse &&
|
(reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) &&
|
||||||
sk2->sk_state != SCTP_SS_LISTENING))
|
sk2->sk_state != SCTP_SS_LISTENING))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -7549,12 +7596,12 @@ pp_not_found:
|
||||||
* SO_REUSEADDR on this socket -sk-).
|
* SO_REUSEADDR on this socket -sk-).
|
||||||
*/
|
*/
|
||||||
if (hlist_empty(&pp->owner)) {
|
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;
|
pp->fastreuse = 1;
|
||||||
else
|
else
|
||||||
pp->fastreuse = 0;
|
pp->fastreuse = 0;
|
||||||
} else if (pp->fastreuse &&
|
} else if (pp->fastreuse &&
|
||||||
(!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING))
|
(!reuse || sk->sk_state == SCTP_SS_LISTENING))
|
||||||
pp->fastreuse = 0;
|
pp->fastreuse = 0;
|
||||||
|
|
||||||
/* We are set, so fill up all the data in the hash table
|
/* 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;
|
err = 0;
|
||||||
sctp_unhash_endpoint(ep);
|
sctp_unhash_endpoint(ep);
|
||||||
sk->sk_state = SCTP_SS_CLOSED;
|
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;
|
sctp_sk(sk)->bind_hash->fastreuse = 1;
|
||||||
goto out;
|
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_tx = sk->sk_no_check_tx;
|
||||||
newsk->sk_no_check_rx = sk->sk_no_check_rx;
|
newsk->sk_no_check_rx = sk->sk_no_check_rx;
|
||||||
newsk->sk_reuse = sk->sk_reuse;
|
newsk->sk_reuse = sk->sk_reuse;
|
||||||
|
sctp_sk(newsk)->reuse = sp->reuse;
|
||||||
|
|
||||||
newsk->sk_shutdown = sk->sk_shutdown;
|
newsk->sk_shutdown = sk->sk_shutdown;
|
||||||
newsk->sk_destruct = sctp_destruct_sock;
|
newsk->sk_destruct = sctp_destruct_sock;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue