summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2018-11-12 05:27:16 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-12 12:09:51 -0500
commit76c6d988aeb3c15d57ea0c245a3b5f27802c1fbe (patch)
tree5508ea6085cda96f528f98229a2317536b776bad
parent532ae2f10e6eab2ec66ecad805d57d3d70cea020 (diff)
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 <nhorman@tuxdriver.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sctp/sctp.h2
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--net/core/sock_reuseport.c1
-rw-r--r--net/sctp/bind_addr.c28
-rw-r--r--net/sctp/input.c60
-rw-r--r--net/sctp/socket.c3
6 files changed, 85 insertions, 11 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 9a3b48a35e90..cdf2e80abc44 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -152,7 +152,7 @@ int sctp_primitive_RECONF(struct net *net, struct sctp_association *asoc,
152 */ 152 */
153int sctp_rcv(struct sk_buff *skb); 153int sctp_rcv(struct sk_buff *skb);
154int sctp_v4_err(struct sk_buff *skb, u32 info); 154int sctp_v4_err(struct sk_buff *skb, u32 info);
155void sctp_hash_endpoint(struct sctp_endpoint *); 155int sctp_hash_endpoint(struct sctp_endpoint *ep);
156void sctp_unhash_endpoint(struct sctp_endpoint *); 156void sctp_unhash_endpoint(struct sctp_endpoint *);
157struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *, 157struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
158 struct sctphdr *, struct sctp_association **, 158 struct sctphdr *, struct sctp_association **,
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index a11f93790476..15d017f33a46 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1190,6 +1190,8 @@ int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *,
1190 struct sctp_sock *, struct sctp_sock *); 1190 struct sctp_sock *, struct sctp_sock *);
1191int sctp_bind_addr_state(const struct sctp_bind_addr *bp, 1191int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
1192 const union sctp_addr *addr); 1192 const union sctp_addr *addr);
1193int sctp_bind_addrs_check(struct sctp_sock *sp,
1194 struct sctp_sock *sp2, int cnt2);
1193union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, 1195union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
1194 const union sctp_addr *addrs, 1196 const union sctp_addr *addrs,
1195 int addrcnt, 1197 int addrcnt,
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index ba5cba56f574..d8fe3e549373 100644
--- a/net/core/sock_reuseport.c
+++ b/net/core/sock_reuseport.c
@@ -187,6 +187,7 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2, bool bind_inany)
187 call_rcu(&old_reuse->rcu, reuseport_free_rcu); 187 call_rcu(&old_reuse->rcu, reuseport_free_rcu);
188 return 0; 188 return 0;
189} 189}
190EXPORT_SYMBOL(reuseport_add_sock);
190 191
191void reuseport_detach_sock(struct sock *sk) 192void reuseport_detach_sock(struct sock *sk)
192{ 193{
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 7df3704982f5..ebf28adba789 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -337,6 +337,34 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
337 return match; 337 return match;
338} 338}
339 339
340int 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;
360next:
361 cnt++;
362 }
363 rcu_read_unlock();
364
365 return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
366}
367
340/* Does the address 'addr' conflict with any addresses in 368/* Does the address 'addr' conflict with any addresses in
341 * the bp. 369 * the bp.
342 */ 370 */
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 00f995e37795..d7a649d240e5 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -724,43 +724,87 @@ discard:
724} 724}
725 725
726/* Insert endpoint into the hash table. */ 726/* Insert endpoint into the hash table. */
727static void __sctp_hash_endpoint(struct sctp_endpoint *ep) 727static int __sctp_hash_endpoint(struct sctp_endpoint *ep)
728{ 728{
729 struct net *net = sock_net(ep->base.sk); 729 struct sock *sk = ep->base.sk;
730 struct sctp_ep_common *epb; 730 struct net *net = sock_net(sk);
731 struct sctp_hashbucket *head; 731 struct sctp_hashbucket *head;
732 struct sctp_ep_common *epb;
732 733
733 epb = &ep->base; 734 epb = &ep->base;
734
735 epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); 735 epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
736 head = &sctp_ep_hashtable[epb->hashent]; 736 head = &sctp_ep_hashtable[epb->hashent];
737 737
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
738 write_lock(&head->lock); 774 write_lock(&head->lock);
739 hlist_add_head(&epb->node, &head->chain); 775 hlist_add_head(&epb->node, &head->chain);
740 write_unlock(&head->lock); 776 write_unlock(&head->lock);
777 return 0;
741} 778}
742 779
743/* Add an endpoint to the hash. Local BH-safe. */ 780/* Add an endpoint to the hash. Local BH-safe. */
744void sctp_hash_endpoint(struct sctp_endpoint *ep) 781int sctp_hash_endpoint(struct sctp_endpoint *ep)
745{ 782{
783 int err;
784
746 local_bh_disable(); 785 local_bh_disable();
747 __sctp_hash_endpoint(ep); 786 err = __sctp_hash_endpoint(ep);
748 local_bh_enable(); 787 local_bh_enable();
788
789 return err;
749} 790}
750 791
751/* Remove endpoint from the hash table. */ 792/* Remove endpoint from the hash table. */
752static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) 793static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
753{ 794{
754 struct net *net = sock_net(ep->base.sk); 795 struct sock *sk = ep->base.sk;
755 struct sctp_hashbucket *head; 796 struct sctp_hashbucket *head;
756 struct sctp_ep_common *epb; 797 struct sctp_ep_common *epb;
757 798
758 epb = &ep->base; 799 epb = &ep->base;
759 800
760 epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); 801 epb->hashent = sctp_ep_hashfn(sock_net(sk), epb->bind_addr.port);
761 802
762 head = &sctp_ep_hashtable[epb->hashent]; 803 head = &sctp_ep_hashtable[epb->hashent];
763 804
805 if (rcu_access_pointer(sk->sk_reuseport_cb))
806 reuseport_detach_sock(sk);
807
764 write_lock(&head->lock); 808 write_lock(&head->lock);
765 hlist_del_init(&epb->node); 809 hlist_del_init(&epb->node);
766 write_unlock(&head->lock); 810 write_unlock(&head->lock);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 739f3e50120d..2e955f1dbe3f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -7852,8 +7852,7 @@ static int sctp_listen_start(struct sock *sk, int backlog)
7852 } 7852 }
7853 7853
7854 sk->sk_max_ack_backlog = backlog; 7854 sk->sk_max_ack_backlog = backlog;
7855 sctp_hash_endpoint(ep); 7855 return sctp_hash_endpoint(ep);
7856 return 0;
7857} 7856}
7858 7857
7859/* 7858/*