@@ -21,6 +21,7 @@
#include <net/ipv6.h>
#include <net/netns/hash.h>
+#include <net/inet_hashtables.h>
struct inet_hashinfo;
@@ -103,6 +104,25 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
const int dif);
int inet6_hash(struct sock *sk);
+
+static inline struct sock *inet6_lookup_run_bpf(struct net *net, u8 protocol,
+ const struct in6_addr *saddr,
+ __be16 sport,
+ const struct in6_addr *daddr,
+ u16 dport)
+{
+ struct bpf_sk_lookup_kern ctx = {
+ .family = AF_INET6,
+ .protocol = protocol,
+ .v6.saddr = *saddr,
+ .v6.daddr = *daddr,
+ .sport = sport,
+ .dport = dport,
+ };
+
+ return bpf_sk_lookup_run(net, &ctx);
+}
+
#endif /* IS_ENABLED(CONFIG_IPV6) */
#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif, __sdif) \
@@ -167,9 +167,22 @@ struct sock *inet6_lookup_listener(struct net *net,
const unsigned short hnum, const int dif, const int sdif)
{
struct inet_listen_hashbucket *ilb2;
- struct sock *result = NULL;
+ struct sock *result, *reuse_sk;
unsigned int hash2;
+ /* Lookup redirect from BPF */
+ result = inet6_lookup_run_bpf(net, hashinfo->protocol,
+ saddr, sport, daddr, hnum);
+ if (IS_ERR(result))
+ return NULL;
+ if (result) {
+ reuse_sk = lookup_reuseport(net, result, skb, doff,
+ saddr, sport, daddr, hnum);
+ if (reuse_sk)
+ result = reuse_sk;
+ goto done;
+ }
+
hash2 = ipv6_portaddr_hash(net, daddr, hnum);
ilb2 = inet_lhash2_bucket(hashinfo, hash2);