Skip to content

Commit 76c6d98

Browse files
lxindavem330
authored andcommitted
sctp: add sock_reuseport for the sock in __sctp_hash_endpoint
This is a part of sk_reuseport support for sctp. It defines a helper sctp_bind_addrs_check() to check if the bind_addrs in two socks are matched. It will add sock_reuseport if they are completely matched, and return err if they are partly matched, and alloc sock_reuseport if all socks are not matched at all. It will work until sk_reuseport support is added in sctp_get_port_local() in the next patch. v1->v2: - use 'laddr->valid && laddr2->valid' check instead as Marcelo pointed in sctp_bind_addrs_check(). Acked-by: Neil Horman <[email protected]> Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 532ae2f commit 76c6d98

File tree

6 files changed

+85
-11
lines changed

6 files changed

+85
-11
lines changed

include/net/sctp/sctp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ int sctp_primitive_RECONF(struct net *net, struct sctp_association *asoc,
152152
*/
153153
int sctp_rcv(struct sk_buff *skb);
154154
int sctp_v4_err(struct sk_buff *skb, u32 info);
155-
void sctp_hash_endpoint(struct sctp_endpoint *);
155+
int sctp_hash_endpoint(struct sctp_endpoint *ep);
156156
void sctp_unhash_endpoint(struct sctp_endpoint *);
157157
struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
158158
struct sctphdr *, struct sctp_association **,

include/net/sctp/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,8 @@ int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *,
11901190
struct sctp_sock *, struct sctp_sock *);
11911191
int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
11921192
const union sctp_addr *addr);
1193+
int sctp_bind_addrs_check(struct sctp_sock *sp,
1194+
struct sctp_sock *sp2, int cnt2);
11931195
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
11941196
const union sctp_addr *addrs,
11951197
int addrcnt,

net/core/sock_reuseport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2, bool bind_inany)
187187
call_rcu(&old_reuse->rcu, reuseport_free_rcu);
188188
return 0;
189189
}
190+
EXPORT_SYMBOL(reuseport_add_sock);
190191

191192
void reuseport_detach_sock(struct sock *sk)
192193
{

net/sctp/bind_addr.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,34 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
337337
return match;
338338
}
339339

340+
int sctp_bind_addrs_check(struct sctp_sock *sp,
341+
struct sctp_sock *sp2, int cnt2)
342+
{
343+
struct sctp_bind_addr *bp2 = &sp2->ep->base.bind_addr;
344+
struct sctp_bind_addr *bp = &sp->ep->base.bind_addr;
345+
struct sctp_sockaddr_entry *laddr, *laddr2;
346+
bool exist = false;
347+
int cnt = 0;
348+
349+
rcu_read_lock();
350+
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
351+
list_for_each_entry_rcu(laddr2, &bp2->address_list, list) {
352+
if (sp->pf->af->cmp_addr(&laddr->a, &laddr2->a) &&
353+
laddr->valid && laddr2->valid) {
354+
exist = true;
355+
goto next;
356+
}
357+
}
358+
cnt = 0;
359+
break;
360+
next:
361+
cnt++;
362+
}
363+
rcu_read_unlock();
364+
365+
return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
366+
}
367+
340368
/* Does the address 'addr' conflict with any addresses in
341369
* the bp.
342370
*/

net/sctp/input.c

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -724,43 +724,87 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
724724
}
725725

726726
/* Insert endpoint into the hash table. */
727-
static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
727+
static int __sctp_hash_endpoint(struct sctp_endpoint *ep)
728728
{
729-
struct net *net = sock_net(ep->base.sk);
730-
struct sctp_ep_common *epb;
729+
struct sock *sk = ep->base.sk;
730+
struct net *net = sock_net(sk);
731731
struct sctp_hashbucket *head;
732+
struct sctp_ep_common *epb;
732733

733734
epb = &ep->base;
734-
735735
epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
736736
head = &sctp_ep_hashtable[epb->hashent];
737737

738+
if (sk->sk_reuseport) {
739+
bool any = sctp_is_ep_boundall(sk);
740+
struct sctp_ep_common *epb2;
741+
struct list_head *list;
742+
int cnt = 0, err = 1;
743+
744+
list_for_each(list, &ep->base.bind_addr.address_list)
745+
cnt++;
746+
747+
sctp_for_each_hentry(epb2, &head->chain) {
748+
struct sock *sk2 = epb2->sk;
749+
750+
if (!net_eq(sock_net(sk2), net) || sk2 == sk ||
751+
!uid_eq(sock_i_uid(sk2), sock_i_uid(sk)) ||
752+
!sk2->sk_reuseport)
753+
continue;
754+
755+
err = sctp_bind_addrs_check(sctp_sk(sk2),
756+
sctp_sk(sk), cnt);
757+
if (!err) {
758+
err = reuseport_add_sock(sk, sk2, any);
759+
if (err)
760+
return err;
761+
break;
762+
} else if (err < 0) {
763+
return err;
764+
}
765+
}
766+
767+
if (err) {
768+
err = reuseport_alloc(sk, any);
769+
if (err)
770+
return err;
771+
}
772+
}
773+
738774
write_lock(&head->lock);
739775
hlist_add_head(&epb->node, &head->chain);
740776
write_unlock(&head->lock);
777+
return 0;
741778
}
742779

743780
/* Add an endpoint to the hash. Local BH-safe. */
744-
void sctp_hash_endpoint(struct sctp_endpoint *ep)
781+
int sctp_hash_endpoint(struct sctp_endpoint *ep)
745782
{
783+
int err;
784+
746785
local_bh_disable();
747-
__sctp_hash_endpoint(ep);
786+
err = __sctp_hash_endpoint(ep);
748787
local_bh_enable();
788+
789+
return err;
749790
}
750791

751792
/* Remove endpoint from the hash table. */
752793
static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
753794
{
754-
struct net *net = sock_net(ep->base.sk);
795+
struct sock *sk = ep->base.sk;
755796
struct sctp_hashbucket *head;
756797
struct sctp_ep_common *epb;
757798

758799
epb = &ep->base;
759800

760-
epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
801+
epb->hashent = sctp_ep_hashfn(sock_net(sk), epb->bind_addr.port);
761802

762803
head = &sctp_ep_hashtable[epb->hashent];
763804

805+
if (rcu_access_pointer(sk->sk_reuseport_cb))
806+
reuseport_detach_sock(sk);
807+
764808
write_lock(&head->lock);
765809
hlist_del_init(&epb->node);
766810
write_unlock(&head->lock);

net/sctp/socket.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7852,8 +7852,7 @@ static int sctp_listen_start(struct sock *sk, int backlog)
78527852
}
78537853

78547854
sk->sk_max_ack_backlog = backlog;
7855-
sctp_hash_endpoint(ep);
7856-
return 0;
7855+
return sctp_hash_endpoint(ep);
78577856
}
78587857

78597858
/*

0 commit comments

Comments
 (0)