#define CONNECT_PORT 4321
 #define TEST_DADDR (0xC0A80203)
 #define NS_SELF "/proc/self/ns/net"
+#define SERVER_MAP_PATH "/sys/fs/bpf/tc/globals/server_map"
 
 static const struct timeval timeo_sec = { .tv_sec = 3 };
 static const size_t timeo_optlen = sizeof(timeo_sec);
                TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true),
        };
        int server = -1;
+       int server_map;
        int self_net;
 
        self_net = open(NS_SELF, O_RDONLY);
                goto cleanup;
        }
 
+       server_map = bpf_obj_get(SERVER_MAP_PATH);
+       if (CHECK_FAIL(server_map < 0)) {
+               perror("Unable to open " SERVER_MAP_PATH);
+               goto cleanup;
+       }
+
        for (int i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) {
                struct test_sk_cfg *test = &tests[i];
                const struct sockaddr *addr;
+               const int zero = 0;
+               int err;
 
                if (!test__start_subtest(test->name))
                        continue;
                addr = (const struct sockaddr *)test->addr;
                server = start_server(addr, test->len, test->type);
                if (server == -1)
-                       goto cleanup;
+                       goto close;
+
+               err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY);
+               if (CHECK_FAIL(err)) {
+                       perror("Unable to update server_map");
+                       goto close;
+               }
 
                /* connect to unbound ports */
                prepare_addr(test->addr, test->family, CONNECT_PORT,
 
 close:
        close(server);
+       close(server_map);
 cleanup:
+       if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
+               perror("Unable to unlink " SERVER_MAP_PATH);
        if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
                perror("Failed to setns("NS_SELF")");
        close(self_net);
 
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_endian.h>
 
+/* Pin map under /sys/fs/bpf/tc/globals/<map name> */
+#define PIN_GLOBAL_NS 2
+
+/* Must match struct bpf_elf_map layout from iproute2 */
+struct {
+       __u32 type;
+       __u32 size_key;
+       __u32 size_value;
+       __u32 max_elem;
+       __u32 flags;
+       __u32 id;
+       __u32 pinning;
+} server_map SEC("maps") = {
+       .type = BPF_MAP_TYPE_SOCKMAP,
+       .size_key = sizeof(int),
+       .size_value  = sizeof(__u64),
+       .max_elem = 1,
+       .pinning = PIN_GLOBAL_NS,
+};
+
 int _version SEC("version") = 1;
 char _license[] SEC("license") = "GPL";
 
 {
        struct bpf_sock_tuple ln = {0};
        struct bpf_sock *sk;
+       const int zero = 0;
        size_t tuple_len;
+       __be16 dport;
        int ret;
 
        tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6);
        if (sk)
                goto assign;
 
-       if (ipv4) {
-               if (tuple->ipv4.dport != bpf_htons(4321))
-                       return TC_ACT_OK;
-
-               ln.ipv4.daddr = bpf_htonl(0x7f000001);
-               ln.ipv4.dport = bpf_htons(1234);
-
-               sk = bpf_sk_lookup_udp(skb, &ln, sizeof(ln.ipv4),
-                                       BPF_F_CURRENT_NETNS, 0);
-       } else {
-               if (tuple->ipv6.dport != bpf_htons(4321))
-                       return TC_ACT_OK;
-
-               /* Upper parts of daddr are already zero. */
-               ln.ipv6.daddr[3] = bpf_htonl(0x1);
-               ln.ipv6.dport = bpf_htons(1234);
-
-               sk = bpf_sk_lookup_udp(skb, &ln, sizeof(ln.ipv6),
-                                       BPF_F_CURRENT_NETNS, 0);
-       }
+       dport = ipv4 ? tuple->ipv4.dport : tuple->ipv6.dport;
+       if (dport != bpf_htons(4321))
+               return TC_ACT_OK;
 
-       /* workaround: We can't do a single socket lookup here, because then
-        * the compiler will likely spill tuple_len to the stack. This makes it
-        * lose all bounds information in the verifier, which then rejects the
-        * call as unsafe.
-        */
+       sk = bpf_map_lookup_elem(&server_map, &zero);
        if (!sk)
                return TC_ACT_SHOT;
 
 {
        struct bpf_sock_tuple ln = {0};
        struct bpf_sock *sk;
+       const int zero = 0;
        size_t tuple_len;
+       __be16 dport;
        int ret;
 
        tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6);
                bpf_sk_release(sk);
        }
 
-       if (ipv4) {
-               if (tuple->ipv4.dport != bpf_htons(4321))
-                       return TC_ACT_OK;
+       dport = ipv4 ? tuple->ipv4.dport : tuple->ipv6.dport;
+       if (dport != bpf_htons(4321))
+               return TC_ACT_OK;
 
-               ln.ipv4.daddr = bpf_htonl(0x7f000001);
-               ln.ipv4.dport = bpf_htons(1234);
-
-               sk = bpf_skc_lookup_tcp(skb, &ln, sizeof(ln.ipv4),
-                                       BPF_F_CURRENT_NETNS, 0);
-       } else {
-               if (tuple->ipv6.dport != bpf_htons(4321))
-                       return TC_ACT_OK;
-
-               /* Upper parts of daddr are already zero. */
-               ln.ipv6.daddr[3] = bpf_htonl(0x1);
-               ln.ipv6.dport = bpf_htons(1234);
-
-               sk = bpf_skc_lookup_tcp(skb, &ln, sizeof(ln.ipv6),
-                                       BPF_F_CURRENT_NETNS, 0);
-       }
-
-       /* workaround: We can't do a single socket lookup here, because then
-        * the compiler will likely spill tuple_len to the stack. This makes it
-        * lose all bounds information in the verifier, which then rejects the
-        * call as unsafe.
-        */
+       sk = bpf_map_lookup_elem(&server_map, &zero);
        if (!sk)
                return TC_ACT_SHOT;