Re: [PATCH net-next 2/3] sctp: add sock_reuseport for the sock in __sctp_hash_endpoint

2018-11-12 Thread Xin Long
On Mon, Oct 22, 2018 at 11:15 PM Marcelo Ricardo Leitner
 wrote:
>
> On Sun, Oct 21, 2018 at 12:43:37PM +0800, Xin Long wrote:
> > 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.
> >
> > Signed-off-by: Xin Long 
> > ---
> >  include/net/sctp/sctp.h|  2 +-
> >  include/net/sctp/structs.h |  2 ++
> >  net/core/sock_reuseport.c  |  1 +
> >  net/sctp/bind_addr.c   | 28 ++
> >  net/sctp/input.c   | 60 
> > +++---
> >  net/sctp/socket.c  |  3 +--
> >  6 files changed, 85 insertions(+), 11 deletions(-)
> >
> > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> > index 8c2caa3..b8cd58d 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,
> >   */
> >  int sctp_rcv(struct sk_buff *skb);
> >  void sctp_v4_err(struct sk_buff *skb, u32 info);
> > -void sctp_hash_endpoint(struct sctp_endpoint *);
> > +int sctp_hash_endpoint(struct sctp_endpoint *ep);
> >  void sctp_unhash_endpoint(struct sctp_endpoint *);
> >  struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
> >struct sctphdr *, struct sctp_association **,
> > diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> > index a11f937..15d017f 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 *,
> >struct sctp_sock *, struct sctp_sock *);
> >  int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
> >const union sctp_addr *addr);
> > +int sctp_bind_addrs_check(struct sctp_sock *sp,
> > +   struct sctp_sock *sp2, int cnt2);
> >  union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr*bp,
> >   const union sctp_addr   *addrs,
> >   int addrcnt,
> > diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
> > index ba5cba5..d8fe3e5 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)
> >   call_rcu(_reuse->rcu, reuseport_free_rcu);
> >   return 0;
> >  }
> > +EXPORT_SYMBOL(reuseport_add_sock);
> >
> >  void reuseport_detach_sock(struct sock *sk)
> >  {
> > diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> > index 7df3704..78d0d93 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,
> >   return match;
> >  }
> >
> > +int sctp_bind_addrs_check(struct sctp_sock *sp,
> > +   struct sctp_sock *sp2, int cnt2)
> > +{
> > + struct sctp_bind_addr *bp2 = >ep->base.bind_addr;
> > + struct sctp_bind_addr *bp = >ep->base.bind_addr;
> > + struct sctp_sockaddr_entry *laddr, *laddr2;
> > + bool exist = false;
> > + int cnt = 0;
> > +
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(laddr, >address_list, list) {
> > + list_for_each_entry_rcu(laddr2, >address_list, list) {
> > + if (sp->pf->af->cmp_addr(>a, >a) &&
> > + laddr->valid == laddr2->valid) {
>
> I think by here in the normal run laddr2->valid will always be true,
> but as is it gives the impression that it accepts 0 == 0 too, which
> would be bad.  May be on a fast BINDX_REM/BINDX_ADD it could trigger
> laddr2->valid = 0 in there, not sure.
>
> Anyway, may be '... laddr->valid && laddr2->valid' instead or you
> really want to allow the 0 == 0 case?
>
will improve it in v2. thanks.

> > + exist = true;
> > + goto next;
> > + }
> > + }
> > + cnt = 0;
> > + break;
> > +next:
> > + cnt++;
> > + }
> > + rcu_read_unlock();
> > +
> > + return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
> > +}
> > +
> >  /* Does the address 'addr' conflict with any addresses in
> >   * the bp.
> >   */
> > diff --git a/net/sctp/input.c b/net/sctp/input.c
> > index 60ede89..6bfeb10 100644
> > --- a/net/sctp/input.c
> > +++ b/net/sctp/input.c
> > @@ -723,43 +723,87 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
> >  }
> >
> >  /* Insert endpoint into the hash table.  */
> > -static void 

Re: [PATCH net-next 2/3] sctp: add sock_reuseport for the sock in __sctp_hash_endpoint

2018-10-22 Thread Marcelo Ricardo Leitner
On Sun, Oct 21, 2018 at 12:43:37PM +0800, Xin Long wrote:
> 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.
> 
> Signed-off-by: Xin Long 
> ---
>  include/net/sctp/sctp.h|  2 +-
>  include/net/sctp/structs.h |  2 ++
>  net/core/sock_reuseport.c  |  1 +
>  net/sctp/bind_addr.c   | 28 ++
>  net/sctp/input.c   | 60 
> +++---
>  net/sctp/socket.c  |  3 +--
>  6 files changed, 85 insertions(+), 11 deletions(-)
> 
> diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> index 8c2caa3..b8cd58d 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,
>   */
>  int sctp_rcv(struct sk_buff *skb);
>  void sctp_v4_err(struct sk_buff *skb, u32 info);
> -void sctp_hash_endpoint(struct sctp_endpoint *);
> +int sctp_hash_endpoint(struct sctp_endpoint *ep);
>  void sctp_unhash_endpoint(struct sctp_endpoint *);
>  struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
>struct sctphdr *, struct sctp_association **,
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index a11f937..15d017f 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 *,
>struct sctp_sock *, struct sctp_sock *);
>  int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
>const union sctp_addr *addr);
> +int sctp_bind_addrs_check(struct sctp_sock *sp,
> +   struct sctp_sock *sp2, int cnt2);
>  union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr*bp,
>   const union sctp_addr   *addrs,
>   int addrcnt,
> diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
> index ba5cba5..d8fe3e5 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)
>   call_rcu(_reuse->rcu, reuseport_free_rcu);
>   return 0;
>  }
> +EXPORT_SYMBOL(reuseport_add_sock);
>  
>  void reuseport_detach_sock(struct sock *sk)
>  {
> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> index 7df3704..78d0d93 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,
>   return match;
>  }
>  
> +int sctp_bind_addrs_check(struct sctp_sock *sp,
> +   struct sctp_sock *sp2, int cnt2)
> +{
> + struct sctp_bind_addr *bp2 = >ep->base.bind_addr;
> + struct sctp_bind_addr *bp = >ep->base.bind_addr;
> + struct sctp_sockaddr_entry *laddr, *laddr2;
> + bool exist = false;
> + int cnt = 0;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(laddr, >address_list, list) {
> + list_for_each_entry_rcu(laddr2, >address_list, list) {
> + if (sp->pf->af->cmp_addr(>a, >a) &&
> + laddr->valid == laddr2->valid) {

I think by here in the normal run laddr2->valid will always be true,
but as is it gives the impression that it accepts 0 == 0 too, which
would be bad.  May be on a fast BINDX_REM/BINDX_ADD it could trigger
laddr2->valid = 0 in there, not sure.

Anyway, may be '... laddr->valid && laddr2->valid' instead or you
really want to allow the 0 == 0 case?

> + exist = true;
> + goto next;
> + }
> + }
> + cnt = 0;
> + break;
> +next:
> + cnt++;
> + }
> + rcu_read_unlock();
> +
> + return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
> +}
> +
>  /* Does the address 'addr' conflict with any addresses in
>   * the bp.
>   */
> diff --git a/net/sctp/input.c b/net/sctp/input.c
> index 60ede89..6bfeb10 100644
> --- a/net/sctp/input.c
> +++ b/net/sctp/input.c
> @@ -723,43 +723,87 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
>  }
>  
>  /* Insert endpoint into the hash table.  */
> -static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
> +static int __sctp_hash_endpoint(struct sctp_endpoint *ep)
>  {
> - struct net *net = sock_net(ep->base.sk);
> - struct sctp_ep_common *epb;
> + struct sock *sk = ep->base.sk;
> + struct net *net = sock_net(sk);
>   struct sctp_hashbucket *head;
> + 

[PATCH net-next 2/3] sctp: add sock_reuseport for the sock in __sctp_hash_endpoint

2018-10-20 Thread Xin Long
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.

Signed-off-by: Xin Long 
---
 include/net/sctp/sctp.h|  2 +-
 include/net/sctp/structs.h |  2 ++
 net/core/sock_reuseport.c  |  1 +
 net/sctp/bind_addr.c   | 28 ++
 net/sctp/input.c   | 60 +++---
 net/sctp/socket.c  |  3 +--
 6 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 8c2caa3..b8cd58d 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,
  */
 int sctp_rcv(struct sk_buff *skb);
 void sctp_v4_err(struct sk_buff *skb, u32 info);
-void sctp_hash_endpoint(struct sctp_endpoint *);
+int sctp_hash_endpoint(struct sctp_endpoint *ep);
 void sctp_unhash_endpoint(struct sctp_endpoint *);
 struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
 struct sctphdr *, struct sctp_association **,
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index a11f937..15d017f 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 *,
 struct sctp_sock *, struct sctp_sock *);
 int sctp_bind_addr_state(const struct sctp_bind_addr *bp,
 const union sctp_addr *addr);
+int sctp_bind_addrs_check(struct sctp_sock *sp,
+ struct sctp_sock *sp2, int cnt2);
 union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr  *bp,
const union sctp_addr   *addrs,
int addrcnt,
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index ba5cba5..d8fe3e5 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)
call_rcu(_reuse->rcu, reuseport_free_rcu);
return 0;
 }
+EXPORT_SYMBOL(reuseport_add_sock);
 
 void reuseport_detach_sock(struct sock *sk)
 {
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 7df3704..78d0d93 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,
return match;
 }
 
+int sctp_bind_addrs_check(struct sctp_sock *sp,
+ struct sctp_sock *sp2, int cnt2)
+{
+   struct sctp_bind_addr *bp2 = >ep->base.bind_addr;
+   struct sctp_bind_addr *bp = >ep->base.bind_addr;
+   struct sctp_sockaddr_entry *laddr, *laddr2;
+   bool exist = false;
+   int cnt = 0;
+
+   rcu_read_lock();
+   list_for_each_entry_rcu(laddr, >address_list, list) {
+   list_for_each_entry_rcu(laddr2, >address_list, list) {
+   if (sp->pf->af->cmp_addr(>a, >a) &&
+   laddr->valid == laddr2->valid) {
+   exist = true;
+   goto next;
+   }
+   }
+   cnt = 0;
+   break;
+next:
+   cnt++;
+   }
+   rcu_read_unlock();
+
+   return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
+}
+
 /* Does the address 'addr' conflict with any addresses in
  * the bp.
  */
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 60ede89..6bfeb10 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -723,43 +723,87 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
 }
 
 /* Insert endpoint into the hash table.  */
-static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
+static int __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
-   struct net *net = sock_net(ep->base.sk);
-   struct sctp_ep_common *epb;
+   struct sock *sk = ep->base.sk;
+   struct net *net = sock_net(sk);
struct sctp_hashbucket *head;
+   struct sctp_ep_common *epb;
 
epb = >base;
-
epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
head = _ep_hashtable[epb->hashent];
 
+   if (sk->sk_reuseport) {
+   bool any = sctp_is_ep_boundall(sk);
+   struct sctp_ep_common *epb2;
+   struct list_head *list;
+   int cnt = 0, err = 1;
+
+   list_for_each(list, >base.bind_addr.address_list)
+   cnt++;
+
+   sctp_for_each_hentry(epb2, >chain) {
+   struct sock *sk2 = epb2->sk;
+
+