xref: /openbmc/linux/include/net/inet6_hashtables.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12874c5fdSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
2505cbfc5SArnaldo Carvalho de Melo /*
3505cbfc5SArnaldo Carvalho de Melo  * INET		An implementation of the TCP/IP protocol suite for the LINUX
4505cbfc5SArnaldo Carvalho de Melo  *		operating system.  INET is implemented using the BSD Socket
5505cbfc5SArnaldo Carvalho de Melo  *		interface as the means of communication with the user level.
6505cbfc5SArnaldo Carvalho de Melo  *
7505cbfc5SArnaldo Carvalho de Melo  * Authors:	Lotsa people, from code originally in tcp
8505cbfc5SArnaldo Carvalho de Melo  */
9505cbfc5SArnaldo Carvalho de Melo 
10505cbfc5SArnaldo Carvalho de Melo #ifndef _INET6_HASHTABLES_H
11505cbfc5SArnaldo Carvalho de Melo #define _INET6_HASHTABLES_H
12505cbfc5SArnaldo Carvalho de Melo 
135324a040SArnaldo Carvalho de Melo 
14dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
155324a040SArnaldo Carvalho de Melo #include <linux/in6.h>
165324a040SArnaldo Carvalho de Melo #include <linux/ipv6.h>
17505cbfc5SArnaldo Carvalho de Melo #include <linux/types.h>
18b3da2cf3SDavid S. Miller #include <linux/jhash.h>
19b3da2cf3SDavid S. Miller 
20b3da2cf3SDavid S. Miller #include <net/inet_sock.h>
21505cbfc5SArnaldo Carvalho de Melo 
225324a040SArnaldo Carvalho de Melo #include <net/ipv6.h>
230b441916SPavel Emelyanov #include <net/netns/hash.h>
245324a040SArnaldo Carvalho de Melo 
25505cbfc5SArnaldo Carvalho de Melo struct inet_hashinfo;
26505cbfc5SArnaldo Carvalho de Melo 
__inet6_ehashfn(const u32 lhash,const u16 lport,const u32 fhash,const __be16 fport,const u32 initval)27b50026b5SHannes Frederic Sowa static inline unsigned int __inet6_ehashfn(const u32 lhash,
28b50026b5SHannes Frederic Sowa 				    const u16 lport,
29b50026b5SHannes Frederic Sowa 				    const u32 fhash,
30b50026b5SHannes Frederic Sowa 				    const __be16 fport,
31b50026b5SHannes Frederic Sowa 				    const u32 initval)
325324a040SArnaldo Carvalho de Melo {
33b50026b5SHannes Frederic Sowa 	const u32 ports = (((u32)lport) << 16) | (__force u32)fport;
34b50026b5SHannes Frederic Sowa 	return jhash_3words(lhash, fhash, ports, initval);
355324a040SArnaldo Carvalho de Melo }
365324a040SArnaldo Carvalho de Melo 
375324a040SArnaldo Carvalho de Melo /*
385324a040SArnaldo Carvalho de Melo  * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
395324a040SArnaldo Carvalho de Melo  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
405324a040SArnaldo Carvalho de Melo  *
415324a040SArnaldo Carvalho de Melo  * The sockhash lock must be held as a reader here.
425324a040SArnaldo Carvalho de Melo  */
431fd51155SJoe Perches struct sock *__inet6_lookup_established(struct net *net,
44d86e0dacSPavel Emelyanov 					struct inet_hashinfo *hashinfo,
455324a040SArnaldo Carvalho de Melo 					const struct in6_addr *saddr,
46d2ecd9ccSAl Viro 					const __be16 sport,
475324a040SArnaldo Carvalho de Melo 					const struct in6_addr *daddr,
484297a0efSDavid Ahern 					const u16 hnum, const int dif,
494297a0efSDavid Ahern 					const int sdif);
505324a040SArnaldo Carvalho de Melo 
510f495f76SLorenz Bauer typedef u32 (inet6_ehashfn_t)(const struct net *net,
520f495f76SLorenz Bauer 			       const struct in6_addr *laddr, const u16 lport,
530f495f76SLorenz Bauer 			       const struct in6_addr *faddr, const __be16 fport);
540f495f76SLorenz Bauer 
550f495f76SLorenz Bauer inet6_ehashfn_t inet6_ehashfn;
560f495f76SLorenz Bauer 
570f495f76SLorenz Bauer INDIRECT_CALLABLE_DECLARE(inet6_ehashfn_t udp6_ehashfn);
580f495f76SLorenz Bauer 
59ce796e60SLorenz Bauer struct sock *inet6_lookup_reuseport(struct net *net, struct sock *sk,
60ce796e60SLorenz Bauer 				    struct sk_buff *skb, int doff,
61ce796e60SLorenz Bauer 				    const struct in6_addr *saddr,
62ce796e60SLorenz Bauer 				    __be16 sport,
63ce796e60SLorenz Bauer 				    const struct in6_addr *daddr,
640f495f76SLorenz Bauer 				    unsigned short hnum,
650f495f76SLorenz Bauer 				    inet6_ehashfn_t *ehashfn);
66ce796e60SLorenz Bauer 
671fd51155SJoe Perches struct sock *inet6_lookup_listener(struct net *net,
68d86e0dacSPavel Emelyanov 				   struct inet_hashinfo *hashinfo,
69a583636aSCraig Gallek 				   struct sk_buff *skb, int doff,
705ba24953STom Herbert 				   const struct in6_addr *saddr,
715ba24953STom Herbert 				   const __be16 sport,
725324a040SArnaldo Carvalho de Melo 				   const struct in6_addr *daddr,
734297a0efSDavid Ahern 				   const unsigned short hnum,
744297a0efSDavid Ahern 				   const int dif, const int sdif);
755324a040SArnaldo Carvalho de Melo 
766c886db2SLorenz Bauer struct sock *inet6_lookup_run_sk_lookup(struct net *net,
776c886db2SLorenz Bauer 					int protocol,
786c886db2SLorenz Bauer 					struct sk_buff *skb, int doff,
796c886db2SLorenz Bauer 					const struct in6_addr *saddr,
806c886db2SLorenz Bauer 					const __be16 sport,
816c886db2SLorenz Bauer 					const struct in6_addr *daddr,
826c886db2SLorenz Bauer 					const u16 hnum, const int dif,
836c886db2SLorenz Bauer 					inet6_ehashfn_t *ehashfn);
846c886db2SLorenz Bauer 
__inet6_lookup(struct net * net,struct inet_hashinfo * hashinfo,struct sk_buff * skb,int doff,const struct in6_addr * saddr,const __be16 sport,const struct in6_addr * daddr,const u16 hnum,const int dif,const int sdif,bool * refcounted)85d86e0dacSPavel Emelyanov static inline struct sock *__inet6_lookup(struct net *net,
86d86e0dacSPavel Emelyanov 					  struct inet_hashinfo *hashinfo,
87a583636aSCraig Gallek 					  struct sk_buff *skb, int doff,
885324a040SArnaldo Carvalho de Melo 					  const struct in6_addr *saddr,
89d2ecd9ccSAl Viro 					  const __be16 sport,
905324a040SArnaldo Carvalho de Melo 					  const struct in6_addr *daddr,
915324a040SArnaldo Carvalho de Melo 					  const u16 hnum,
924297a0efSDavid Ahern 					  const int dif, const int sdif,
933b24d854SEric Dumazet 					  bool *refcounted)
945324a040SArnaldo Carvalho de Melo {
95d86e0dacSPavel Emelyanov 	struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr,
964297a0efSDavid Ahern 						     sport, daddr, hnum,
974297a0efSDavid Ahern 						     dif, sdif);
983b24d854SEric Dumazet 	*refcounted = true;
995324a040SArnaldo Carvalho de Melo 	if (sk)
1005324a040SArnaldo Carvalho de Melo 		return sk;
1013b24d854SEric Dumazet 	*refcounted = false;
102a583636aSCraig Gallek 	return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
1034297a0efSDavid Ahern 				     daddr, hnum, dif, sdif);
1045324a040SArnaldo Carvalho de Melo }
1055324a040SArnaldo Carvalho de Melo 
1069c02bec9SLorenz Bauer static inline
inet6_steal_sock(struct net * net,struct sk_buff * skb,int doff,const struct in6_addr * saddr,const __be16 sport,const struct in6_addr * daddr,const __be16 dport,bool * refcounted,inet6_ehashfn_t * ehashfn)1079c02bec9SLorenz Bauer struct sock *inet6_steal_sock(struct net *net, struct sk_buff *skb, int doff,
1089c02bec9SLorenz Bauer 			      const struct in6_addr *saddr, const __be16 sport,
1099c02bec9SLorenz Bauer 			      const struct in6_addr *daddr, const __be16 dport,
1109c02bec9SLorenz Bauer 			      bool *refcounted, inet6_ehashfn_t *ehashfn)
1119c02bec9SLorenz Bauer {
1129c02bec9SLorenz Bauer 	struct sock *sk, *reuse_sk;
1139c02bec9SLorenz Bauer 	bool prefetched;
1149c02bec9SLorenz Bauer 
1159c02bec9SLorenz Bauer 	sk = skb_steal_sock(skb, refcounted, &prefetched);
1169c02bec9SLorenz Bauer 	if (!sk)
1179c02bec9SLorenz Bauer 		return NULL;
1189c02bec9SLorenz Bauer 
119*8897562fSLorenz Bauer 	if (!prefetched || !sk_fullsock(sk))
1209c02bec9SLorenz Bauer 		return sk;
1219c02bec9SLorenz Bauer 
1229c02bec9SLorenz Bauer 	if (sk->sk_protocol == IPPROTO_TCP) {
1239c02bec9SLorenz Bauer 		if (sk->sk_state != TCP_LISTEN)
1249c02bec9SLorenz Bauer 			return sk;
1259c02bec9SLorenz Bauer 	} else if (sk->sk_protocol == IPPROTO_UDP) {
1269c02bec9SLorenz Bauer 		if (sk->sk_state != TCP_CLOSE)
1279c02bec9SLorenz Bauer 			return sk;
1289c02bec9SLorenz Bauer 	} else {
1299c02bec9SLorenz Bauer 		return sk;
1309c02bec9SLorenz Bauer 	}
1319c02bec9SLorenz Bauer 
1329c02bec9SLorenz Bauer 	reuse_sk = inet6_lookup_reuseport(net, sk, skb, doff,
1339c02bec9SLorenz Bauer 					  saddr, sport, daddr, ntohs(dport),
1349c02bec9SLorenz Bauer 					  ehashfn);
1359c02bec9SLorenz Bauer 	if (!reuse_sk)
1369c02bec9SLorenz Bauer 		return sk;
1379c02bec9SLorenz Bauer 
1389c02bec9SLorenz Bauer 	/* We've chosen a new reuseport sock which is never refcounted. This
1399c02bec9SLorenz Bauer 	 * implies that sk also isn't refcounted.
1409c02bec9SLorenz Bauer 	 */
1419c02bec9SLorenz Bauer 	WARN_ON_ONCE(*refcounted);
1429c02bec9SLorenz Bauer 
1439c02bec9SLorenz Bauer 	return reuse_sk;
1449c02bec9SLorenz Bauer }
1459c02bec9SLorenz Bauer 
__inet6_lookup_skb(struct inet_hashinfo * hashinfo,struct sk_buff * skb,int doff,const __be16 sport,const __be16 dport,int iif,int sdif,bool * refcounted)1469a1f27c4SArnaldo Carvalho de Melo static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
147a583636aSCraig Gallek 					      struct sk_buff *skb, int doff,
1489a1f27c4SArnaldo Carvalho de Melo 					      const __be16 sport,
149870c3151SEric Dumazet 					      const __be16 dport,
1504297a0efSDavid Ahern 					      int iif, int sdif,
1513b24d854SEric Dumazet 					      bool *refcounted)
1529a1f27c4SArnaldo Carvalho de Melo {
1539c02bec9SLorenz Bauer 	struct net *net = dev_net(skb_dst(skb)->dev);
1549c02bec9SLorenz Bauer 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
1559c02bec9SLorenz Bauer 	struct sock *sk;
15623542618SKOVACS Krisztian 
1579c02bec9SLorenz Bauer 	sk = inet6_steal_sock(net, skb, doff, &ip6h->saddr, sport, &ip6h->daddr, dport,
1589c02bec9SLorenz Bauer 			      refcounted, inet6_ehashfn);
1599c02bec9SLorenz Bauer 	if (IS_ERR(sk))
1609c02bec9SLorenz Bauer 		return NULL;
161c7109986SEric Dumazet 	if (sk)
16223542618SKOVACS Krisztian 		return sk;
163c7109986SEric Dumazet 
1649c02bec9SLorenz Bauer 	return __inet6_lookup(net, hashinfo, skb,
1659c02bec9SLorenz Bauer 			      doff, &ip6h->saddr, sport,
1669c02bec9SLorenz Bauer 			      &ip6h->daddr, ntohs(dport),
1674297a0efSDavid Ahern 			      iif, sdif, refcounted);
1689a1f27c4SArnaldo Carvalho de Melo }
1699a1f27c4SArnaldo Carvalho de Melo 
1701fd51155SJoe Perches struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
171a583636aSCraig Gallek 			  struct sk_buff *skb, int doff,
172d2ecd9ccSAl Viro 			  const struct in6_addr *saddr, const __be16 sport,
173d2ecd9ccSAl Viro 			  const struct in6_addr *daddr, const __be16 dport,
174505cbfc5SArnaldo Carvalho de Melo 			  const int dif);
175496611d7SCraig Gallek 
176496611d7SCraig Gallek int inet6_hash(struct sock *sk);
17725de4668SWANG Cong 
inet6_match(struct net * net,const struct sock * sk,const struct in6_addr * saddr,const struct in6_addr * daddr,const __portpair ports,const int dif,const int sdif)1785d368f03SEric Dumazet static inline bool inet6_match(struct net *net, const struct sock *sk,
1795d368f03SEric Dumazet 			       const struct in6_addr *saddr,
1805d368f03SEric Dumazet 			       const struct in6_addr *daddr,
1815d368f03SEric Dumazet 			       const __portpair ports,
1825d368f03SEric Dumazet 			       const int dif, const int sdif)
1835d368f03SEric Dumazet {
1845d368f03SEric Dumazet 	if (!net_eq(sock_net(sk), net) ||
1855d368f03SEric Dumazet 	    sk->sk_family != AF_INET6 ||
1865d368f03SEric Dumazet 	    sk->sk_portpair != ports ||
1875d368f03SEric Dumazet 	    !ipv6_addr_equal(&sk->sk_v6_daddr, saddr) ||
1885d368f03SEric Dumazet 	    !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
1895d368f03SEric Dumazet 		return false;
1905d368f03SEric Dumazet 
191944fd1aeSMike Manning 	/* READ_ONCE() paired with WRITE_ONCE() in sock_bindtoindex_locked() */
192944fd1aeSMike Manning 	return inet_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif,
193944fd1aeSMike Manning 				    sdif);
1945d368f03SEric Dumazet }
1955d368f03SEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */
19625de4668SWANG Cong 
197505cbfc5SArnaldo Carvalho de Melo #endif /* _INET6_HASHTABLES_H */
198