On Thu, 2016-08-18 at 19:29 -0700, David Ahern wrote: > This implements SOCK_DESTROY for UDP sockets similar to what was done > for TCP with commit c1e64e298b8ca ("net: diag: Support destroying TCP > sockets.") A process with a UDP socket targeted for destroy is awakened > and recvmsg fails with ECONNABORTED giving the process notice that > it should close the socket. > > Signed-off-by: David Ahern <d...@cumulusnetworks.com> > --- > include/net/udp.h | 8 ++++++++ > net/ipv4/udp.c | 58 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > net/ipv4/udp_diag.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ > net/ipv6/udp.c | 45 +++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 166 insertions(+) > > diff --git a/include/net/udp.h b/include/net/udp.h > index 8894d7144189..5c3443634b4d 100644 > --- a/include/net/udp.h > +++ b/include/net/udp.h > @@ -251,6 +251,7 @@ int udp_get_port(struct sock *sk, unsigned short snum, > int (*saddr_cmp)(const struct sock *, > const struct sock *)); > void udp_err(struct sk_buff *, u32); > +int udp_abort(struct sock *sk, int err); > int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); > int udp_push_pending_frames(struct sock *sk); > void udp_flush_pending_frames(struct sock *sk); > @@ -274,6 +275,9 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 > saddr, __be16 sport, > struct udp_table *tbl, struct sk_buff *skb); > struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, > __be16 sport, __be16 dport); > +struct sock *udp4_lib_lookup_full(struct net *net, __be32 saddr, > + __be16 sport, __be32 daddr, __be16 dport, > + int dif, struct udp_table *table); > struct sock *udp6_lib_lookup(struct net *net, > const struct in6_addr *saddr, __be16 sport, > const struct in6_addr *daddr, __be16 dport, > @@ -286,6 +290,10 @@ struct sock *__udp6_lib_lookup(struct net *net, > struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, > __be16 sport, __be16 dport); > > +struct sock *udp6_lib_lookup_full(struct net *net, > + const struct in6_addr *saddr, __be16 sport, > + const struct in6_addr *daddr, __be16 dport, > + int dif, struct udp_table *table); > /* > * SNMP statistics for UDP and UDP-Lite > */ > diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c > index e61f7cd65d08..e5b72a7165e1 100644 > --- a/net/ipv4/udp.c > +++ b/net/ipv4/udp.c > @@ -594,6 +594,47 @@ struct sock *udp4_lib_lookup(struct net *net, __be32 > saddr, __be16 sport, > EXPORT_SYMBOL_GPL(udp4_lib_lookup); > #endif > > +/* caller should hold rcu lock */ > +struct sock *udp4_lib_lookup_full(struct net *net, __be32 saddr, > + __be16 sport, __be32 daddr, __be16 dport, > + int dif, struct udp_table *table) > +{ > + struct sock *sk; > + int i; > + > + for (i = 0; i <= table->mask; i++) { > + struct udp_hslot *hslot = &table->hash[i]; > + > + sk_for_each_rcu(sk, &hslot->head) { > + struct inet_sock *inet; > + > + if (!net_eq(sock_net(sk), net) || > + ipv6_only_sock(sk)) > + continue; > + > + if (dif && sk->sk_bound_dev_if != dif) > + continue; > + > + if (sk->sk_family != PF_INET) > + continue; > + > + if (udp_sk(sk)->udp_port_hash != ntohs(sport)) > + continue; > + > + inet = inet_sk(sk); > + if (inet->inet_rcv_saddr != saddr || > + inet->inet_daddr != daddr || > + inet->inet_dport != dport) > + continue; > + > + return sk; > + } > + } > + > + return NULL; > +}
Why are you iterating the whole table ? Normally, udp_hashfn(net, ntohs(dport), udptable->mask) slot should be enough to find all sockets bound to dport.