On Mon, Oct 22, 2018 at 11:15 PM Marcelo Ricardo Leitner <marcelo.leitner@xxxxxxxxx> 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 <lucien.xin@xxxxxxxxx> > > --- > > 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(&old_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 = &sp2->ep->base.bind_addr; > > + struct sctp_bind_addr *bp = &sp->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, &bp->address_list, list) { > > + list_for_each_entry_rcu(laddr2, &bp2->address_list, list) { > > + if (sp->pf->af->cmp_addr(&laddr->a, &laddr2->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 __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 = &ep->base; > > - > > epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); > > head = &sctp_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, &ep->base.bind_addr.address_list) > > + cnt++; > > + > > + sctp_for_each_hentry(epb2, &head->chain) { > > + struct sock *sk2 = epb2->sk; > > + > > + if (!net_eq(sock_net(sk2), net) || sk2 == sk || > > + !uid_eq(sock_i_uid(sk2), sock_i_uid(sk)) || > > + !sk2->sk_reuseport) > > + continue; > > + > > + err = sctp_bind_addrs_check(sctp_sk(sk2), > > + sctp_sk(sk), cnt); > > + if (!err) { > > + err = reuseport_add_sock(sk, sk2, any); > > + if (err) > > + return err; > > + break; > > + } else if (err < 0) { > > + return err; > > + } > > + } > > + > > + if (err) { > > + err = reuseport_alloc(sk, any); > > + if (err) > > + return err; > > + } > > + } > > + > > write_lock(&head->lock); > > hlist_add_head(&epb->node, &head->chain); > > write_unlock(&head->lock); > > + return 0; > > } > > > > /* Add an endpoint to the hash. Local BH-safe. */ > > -void sctp_hash_endpoint(struct sctp_endpoint *ep) > > +int sctp_hash_endpoint(struct sctp_endpoint *ep) > > { > > + int err; > > + > > local_bh_disable(); > > - __sctp_hash_endpoint(ep); > > + err = __sctp_hash_endpoint(ep); > > local_bh_enable(); > > + > > + return err; > > } > > > > /* Remove endpoint from the hash table. */ > > static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) > > { > > - struct net *net = sock_net(ep->base.sk); > > + struct sock *sk = ep->base.sk; > > struct sctp_hashbucket *head; > > struct sctp_ep_common *epb; > > > > epb = &ep->base; > > > > - epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port); > > + epb->hashent = sctp_ep_hashfn(sock_net(sk), epb->bind_addr.port); > > > > head = &sctp_ep_hashtable[epb->hashent]; > > > > + if (rcu_access_pointer(sk->sk_reuseport_cb)) > > + reuseport_detach_sock(sk); > > + > > write_lock(&head->lock); > > hlist_del_init(&epb->node); > > write_unlock(&head->lock); > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > > index fc0386e..44e7d8c 100644 > > --- a/net/sctp/socket.c > > +++ b/net/sctp/socket.c > > @@ -7850,8 +7850,7 @@ static int sctp_listen_start(struct sock *sk, int backlog) > > } > > > > sk->sk_max_ack_backlog = backlog; > > - sctp_hash_endpoint(ep); > > - return 0; > > + return sctp_hash_endpoint(ep); > > } > > > > /* > > -- > > 2.1.0 > >