cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_sk_lookup.c (19033B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2// Copyright (c) 2020 Cloudflare
      3
      4#include <errno.h>
      5#include <stdbool.h>
      6#include <stddef.h>
      7#include <linux/bpf.h>
      8#include <linux/in.h>
      9#include <sys/socket.h>
     10
     11#include <bpf/bpf_endian.h>
     12#include <bpf/bpf_helpers.h>
     13
     14#define IP4(a, b, c, d)					\
     15	bpf_htonl((((__u32)(a) & 0xffU) << 24) |	\
     16		  (((__u32)(b) & 0xffU) << 16) |	\
     17		  (((__u32)(c) & 0xffU) <<  8) |	\
     18		  (((__u32)(d) & 0xffU) <<  0))
     19#define IP6(aaaa, bbbb, cccc, dddd)			\
     20	{ bpf_htonl(aaaa), bpf_htonl(bbbb), bpf_htonl(cccc), bpf_htonl(dddd) }
     21
     22/* Macros for least-significant byte and word accesses. */
     23#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     24#define LSE_INDEX(index, size) (index)
     25#else
     26#define LSE_INDEX(index, size) ((size) - (index) - 1)
     27#endif
     28#define LSB(value, index)				\
     29	(((__u8 *)&(value))[LSE_INDEX((index), sizeof(value))])
     30#define LSW(value, index)				\
     31	(((__u16 *)&(value))[LSE_INDEX((index), sizeof(value) / 2)])
     32
     33#define MAX_SOCKS 32
     34
     35struct {
     36	__uint(type, BPF_MAP_TYPE_SOCKMAP);
     37	__uint(max_entries, MAX_SOCKS);
     38	__type(key, __u32);
     39	__type(value, __u64);
     40} redir_map SEC(".maps");
     41
     42struct {
     43	__uint(type, BPF_MAP_TYPE_ARRAY);
     44	__uint(max_entries, 2);
     45	__type(key, int);
     46	__type(value, int);
     47} run_map SEC(".maps");
     48
     49enum {
     50	PROG1 = 0,
     51	PROG2,
     52};
     53
     54enum {
     55	SERVER_A = 0,
     56	SERVER_B,
     57};
     58
     59/* Addressable key/value constants for convenience */
     60static const int KEY_PROG1 = PROG1;
     61static const int KEY_PROG2 = PROG2;
     62static const int PROG_DONE = 1;
     63
     64static const __u32 KEY_SERVER_A = SERVER_A;
     65static const __u32 KEY_SERVER_B = SERVER_B;
     66
     67static const __u16 SRC_PORT = bpf_htons(8008);
     68static const __u32 SRC_IP4 = IP4(127, 0, 0, 2);
     69static const __u32 SRC_IP6[] = IP6(0xfd000000, 0x0, 0x0, 0x00000002);
     70
     71static const __u16 DST_PORT = 7007; /* Host byte order */
     72static const __u32 DST_IP4 = IP4(127, 0, 0, 1);
     73static const __u32 DST_IP6[] = IP6(0xfd000000, 0x0, 0x0, 0x00000001);
     74
     75SEC("sk_lookup")
     76int lookup_pass(struct bpf_sk_lookup *ctx)
     77{
     78	return SK_PASS;
     79}
     80
     81SEC("sk_lookup")
     82int lookup_drop(struct bpf_sk_lookup *ctx)
     83{
     84	return SK_DROP;
     85}
     86
     87SEC("sk_lookup")
     88int check_ifindex(struct bpf_sk_lookup *ctx)
     89{
     90	if (ctx->ingress_ifindex == 1)
     91		return SK_DROP;
     92	return SK_PASS;
     93}
     94
     95SEC("sk_reuseport")
     96int reuseport_pass(struct sk_reuseport_md *ctx)
     97{
     98	return SK_PASS;
     99}
    100
    101SEC("sk_reuseport")
    102int reuseport_drop(struct sk_reuseport_md *ctx)
    103{
    104	return SK_DROP;
    105}
    106
    107/* Redirect packets destined for port DST_PORT to socket at redir_map[0]. */
    108SEC("sk_lookup")
    109int redir_port(struct bpf_sk_lookup *ctx)
    110{
    111	struct bpf_sock *sk;
    112	int err;
    113
    114	if (ctx->local_port != DST_PORT)
    115		return SK_PASS;
    116
    117	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    118	if (!sk)
    119		return SK_PASS;
    120
    121	err = bpf_sk_assign(ctx, sk, 0);
    122	bpf_sk_release(sk);
    123	return err ? SK_DROP : SK_PASS;
    124}
    125
    126/* Redirect packets destined for DST_IP4 address to socket at redir_map[0]. */
    127SEC("sk_lookup")
    128int redir_ip4(struct bpf_sk_lookup *ctx)
    129{
    130	struct bpf_sock *sk;
    131	int err;
    132
    133	if (ctx->family != AF_INET)
    134		return SK_PASS;
    135	if (ctx->local_port != DST_PORT)
    136		return SK_PASS;
    137	if (ctx->local_ip4 != DST_IP4)
    138		return SK_PASS;
    139
    140	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    141	if (!sk)
    142		return SK_PASS;
    143
    144	err = bpf_sk_assign(ctx, sk, 0);
    145	bpf_sk_release(sk);
    146	return err ? SK_DROP : SK_PASS;
    147}
    148
    149/* Redirect packets destined for DST_IP6 address to socket at redir_map[0]. */
    150SEC("sk_lookup")
    151int redir_ip6(struct bpf_sk_lookup *ctx)
    152{
    153	struct bpf_sock *sk;
    154	int err;
    155
    156	if (ctx->family != AF_INET6)
    157		return SK_PASS;
    158	if (ctx->local_port != DST_PORT)
    159		return SK_PASS;
    160	if (ctx->local_ip6[0] != DST_IP6[0] ||
    161	    ctx->local_ip6[1] != DST_IP6[1] ||
    162	    ctx->local_ip6[2] != DST_IP6[2] ||
    163	    ctx->local_ip6[3] != DST_IP6[3])
    164		return SK_PASS;
    165
    166	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    167	if (!sk)
    168		return SK_PASS;
    169
    170	err = bpf_sk_assign(ctx, sk, 0);
    171	bpf_sk_release(sk);
    172	return err ? SK_DROP : SK_PASS;
    173}
    174
    175SEC("sk_lookup")
    176int select_sock_a(struct bpf_sk_lookup *ctx)
    177{
    178	struct bpf_sock *sk;
    179	int err;
    180
    181	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    182	if (!sk)
    183		return SK_PASS;
    184
    185	err = bpf_sk_assign(ctx, sk, 0);
    186	bpf_sk_release(sk);
    187	return err ? SK_DROP : SK_PASS;
    188}
    189
    190SEC("sk_lookup")
    191int select_sock_a_no_reuseport(struct bpf_sk_lookup *ctx)
    192{
    193	struct bpf_sock *sk;
    194	int err;
    195
    196	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    197	if (!sk)
    198		return SK_DROP;
    199
    200	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_NO_REUSEPORT);
    201	bpf_sk_release(sk);
    202	return err ? SK_DROP : SK_PASS;
    203}
    204
    205SEC("sk_reuseport")
    206int select_sock_b(struct sk_reuseport_md *ctx)
    207{
    208	__u32 key = KEY_SERVER_B;
    209	int err;
    210
    211	err = bpf_sk_select_reuseport(ctx, &redir_map, &key, 0);
    212	return err ? SK_DROP : SK_PASS;
    213}
    214
    215/* Check that bpf_sk_assign() returns -EEXIST if socket already selected. */
    216SEC("sk_lookup")
    217int sk_assign_eexist(struct bpf_sk_lookup *ctx)
    218{
    219	struct bpf_sock *sk;
    220	int err, ret;
    221
    222	ret = SK_DROP;
    223	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
    224	if (!sk)
    225		goto out;
    226	err = bpf_sk_assign(ctx, sk, 0);
    227	if (err)
    228		goto out;
    229	bpf_sk_release(sk);
    230
    231	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    232	if (!sk)
    233		goto out;
    234	err = bpf_sk_assign(ctx, sk, 0);
    235	if (err != -EEXIST) {
    236		bpf_printk("sk_assign returned %d, expected %d\n",
    237			   err, -EEXIST);
    238		goto out;
    239	}
    240
    241	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
    242out:
    243	if (sk)
    244		bpf_sk_release(sk);
    245	return ret;
    246}
    247
    248/* Check that bpf_sk_assign(BPF_SK_LOOKUP_F_REPLACE) can override selection. */
    249SEC("sk_lookup")
    250int sk_assign_replace_flag(struct bpf_sk_lookup *ctx)
    251{
    252	struct bpf_sock *sk;
    253	int err, ret;
    254
    255	ret = SK_DROP;
    256	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    257	if (!sk)
    258		goto out;
    259	err = bpf_sk_assign(ctx, sk, 0);
    260	if (err)
    261		goto out;
    262	bpf_sk_release(sk);
    263
    264	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
    265	if (!sk)
    266		goto out;
    267	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
    268	if (err) {
    269		bpf_printk("sk_assign returned %d, expected 0\n", err);
    270		goto out;
    271	}
    272
    273	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
    274out:
    275	if (sk)
    276		bpf_sk_release(sk);
    277	return ret;
    278}
    279
    280/* Check that bpf_sk_assign(sk=NULL) is accepted. */
    281SEC("sk_lookup")
    282int sk_assign_null(struct bpf_sk_lookup *ctx)
    283{
    284	struct bpf_sock *sk = NULL;
    285	int err, ret;
    286
    287	ret = SK_DROP;
    288
    289	err = bpf_sk_assign(ctx, NULL, 0);
    290	if (err) {
    291		bpf_printk("sk_assign returned %d, expected 0\n", err);
    292		goto out;
    293	}
    294
    295	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
    296	if (!sk)
    297		goto out;
    298	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
    299	if (err) {
    300		bpf_printk("sk_assign returned %d, expected 0\n", err);
    301		goto out;
    302	}
    303
    304	if (ctx->sk != sk)
    305		goto out;
    306	err = bpf_sk_assign(ctx, NULL, 0);
    307	if (err != -EEXIST)
    308		goto out;
    309	err = bpf_sk_assign(ctx, NULL, BPF_SK_LOOKUP_F_REPLACE);
    310	if (err)
    311		goto out;
    312	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
    313	if (err)
    314		goto out;
    315
    316	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
    317out:
    318	if (sk)
    319		bpf_sk_release(sk);
    320	return ret;
    321}
    322
    323/* Check that selected sk is accessible through context. */
    324SEC("sk_lookup")
    325int access_ctx_sk(struct bpf_sk_lookup *ctx)
    326{
    327	struct bpf_sock *sk1 = NULL, *sk2 = NULL;
    328	int err, ret;
    329
    330	ret = SK_DROP;
    331
    332	/* Try accessing unassigned (NULL) ctx->sk field */
    333	if (ctx->sk && ctx->sk->family != AF_INET)
    334		goto out;
    335
    336	/* Assign a value to ctx->sk */
    337	sk1 = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    338	if (!sk1)
    339		goto out;
    340	err = bpf_sk_assign(ctx, sk1, 0);
    341	if (err)
    342		goto out;
    343	if (ctx->sk != sk1)
    344		goto out;
    345
    346	/* Access ctx->sk fields */
    347	if (ctx->sk->family != AF_INET ||
    348	    ctx->sk->type != SOCK_STREAM ||
    349	    ctx->sk->state != BPF_TCP_LISTEN)
    350		goto out;
    351
    352	/* Reset selection */
    353	err = bpf_sk_assign(ctx, NULL, BPF_SK_LOOKUP_F_REPLACE);
    354	if (err)
    355		goto out;
    356	if (ctx->sk)
    357		goto out;
    358
    359	/* Assign another socket */
    360	sk2 = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
    361	if (!sk2)
    362		goto out;
    363	err = bpf_sk_assign(ctx, sk2, BPF_SK_LOOKUP_F_REPLACE);
    364	if (err)
    365		goto out;
    366	if (ctx->sk != sk2)
    367		goto out;
    368
    369	/* Access reassigned ctx->sk fields */
    370	if (ctx->sk->family != AF_INET ||
    371	    ctx->sk->type != SOCK_STREAM ||
    372	    ctx->sk->state != BPF_TCP_LISTEN)
    373		goto out;
    374
    375	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
    376out:
    377	if (sk1)
    378		bpf_sk_release(sk1);
    379	if (sk2)
    380		bpf_sk_release(sk2);
    381	return ret;
    382}
    383
    384/* Check narrow loads from ctx fields that support them.
    385 *
    386 * Narrow loads of size >= target field size from a non-zero offset
    387 * are not covered because they give bogus results, that is the
    388 * verifier ignores the offset.
    389 */
    390SEC("sk_lookup")
    391int ctx_narrow_access(struct bpf_sk_lookup *ctx)
    392{
    393	struct bpf_sock *sk;
    394	int err, family;
    395	__u32 val_u32;
    396	bool v4;
    397
    398	v4 = (ctx->family == AF_INET);
    399
    400	/* Narrow loads from family field */
    401	if (LSB(ctx->family, 0) != (v4 ? AF_INET : AF_INET6) ||
    402	    LSB(ctx->family, 1) != 0 || LSB(ctx->family, 2) != 0 || LSB(ctx->family, 3) != 0)
    403		return SK_DROP;
    404	if (LSW(ctx->family, 0) != (v4 ? AF_INET : AF_INET6))
    405		return SK_DROP;
    406
    407	/* Narrow loads from protocol field */
    408	if (LSB(ctx->protocol, 0) != IPPROTO_TCP ||
    409	    LSB(ctx->protocol, 1) != 0 || LSB(ctx->protocol, 2) != 0 || LSB(ctx->protocol, 3) != 0)
    410		return SK_DROP;
    411	if (LSW(ctx->protocol, 0) != IPPROTO_TCP)
    412		return SK_DROP;
    413
    414	/* Narrow loads from remote_port field. Expect SRC_PORT. */
    415	if (LSB(ctx->remote_port, 0) != ((SRC_PORT >> 0) & 0xff) ||
    416	    LSB(ctx->remote_port, 1) != ((SRC_PORT >> 8) & 0xff))
    417		return SK_DROP;
    418	if (LSW(ctx->remote_port, 0) != SRC_PORT)
    419		return SK_DROP;
    420
    421	/*
    422	 * NOTE: 4-byte load from bpf_sk_lookup at remote_port offset
    423	 * is quirky. It gets rewritten by the access converter to a
    424	 * 2-byte load for backward compatibility. Treating the load
    425	 * result as a be16 value makes the code portable across
    426	 * little- and big-endian platforms.
    427	 */
    428	val_u32 = *(__u32 *)&ctx->remote_port;
    429	if (val_u32 != SRC_PORT)
    430		return SK_DROP;
    431
    432	/* Narrow loads from local_port field. Expect DST_PORT. */
    433	if (LSB(ctx->local_port, 0) != ((DST_PORT >> 0) & 0xff) ||
    434	    LSB(ctx->local_port, 1) != ((DST_PORT >> 8) & 0xff) ||
    435	    LSB(ctx->local_port, 2) != 0 || LSB(ctx->local_port, 3) != 0)
    436		return SK_DROP;
    437	if (LSW(ctx->local_port, 0) != DST_PORT)
    438		return SK_DROP;
    439
    440	/* Narrow loads from IPv4 fields */
    441	if (v4) {
    442		/* Expect SRC_IP4 in remote_ip4 */
    443		if (LSB(ctx->remote_ip4, 0) != ((SRC_IP4 >> 0) & 0xff) ||
    444		    LSB(ctx->remote_ip4, 1) != ((SRC_IP4 >> 8) & 0xff) ||
    445		    LSB(ctx->remote_ip4, 2) != ((SRC_IP4 >> 16) & 0xff) ||
    446		    LSB(ctx->remote_ip4, 3) != ((SRC_IP4 >> 24) & 0xff))
    447			return SK_DROP;
    448		if (LSW(ctx->remote_ip4, 0) != ((SRC_IP4 >> 0) & 0xffff) ||
    449		    LSW(ctx->remote_ip4, 1) != ((SRC_IP4 >> 16) & 0xffff))
    450			return SK_DROP;
    451
    452		/* Expect DST_IP4 in local_ip4 */
    453		if (LSB(ctx->local_ip4, 0) != ((DST_IP4 >> 0) & 0xff) ||
    454		    LSB(ctx->local_ip4, 1) != ((DST_IP4 >> 8) & 0xff) ||
    455		    LSB(ctx->local_ip4, 2) != ((DST_IP4 >> 16) & 0xff) ||
    456		    LSB(ctx->local_ip4, 3) != ((DST_IP4 >> 24) & 0xff))
    457			return SK_DROP;
    458		if (LSW(ctx->local_ip4, 0) != ((DST_IP4 >> 0) & 0xffff) ||
    459		    LSW(ctx->local_ip4, 1) != ((DST_IP4 >> 16) & 0xffff))
    460			return SK_DROP;
    461	} else {
    462		/* Expect 0.0.0.0 IPs when family != AF_INET */
    463		if (LSB(ctx->remote_ip4, 0) != 0 || LSB(ctx->remote_ip4, 1) != 0 ||
    464		    LSB(ctx->remote_ip4, 2) != 0 || LSB(ctx->remote_ip4, 3) != 0)
    465			return SK_DROP;
    466		if (LSW(ctx->remote_ip4, 0) != 0 || LSW(ctx->remote_ip4, 1) != 0)
    467			return SK_DROP;
    468
    469		if (LSB(ctx->local_ip4, 0) != 0 || LSB(ctx->local_ip4, 1) != 0 ||
    470		    LSB(ctx->local_ip4, 2) != 0 || LSB(ctx->local_ip4, 3) != 0)
    471			return SK_DROP;
    472		if (LSW(ctx->local_ip4, 0) != 0 || LSW(ctx->local_ip4, 1) != 0)
    473			return SK_DROP;
    474	}
    475
    476	/* Narrow loads from IPv6 fields */
    477	if (!v4) {
    478		/* Expect SRC_IP6 in remote_ip6 */
    479		if (LSB(ctx->remote_ip6[0], 0) != ((SRC_IP6[0] >> 0) & 0xff) ||
    480		    LSB(ctx->remote_ip6[0], 1) != ((SRC_IP6[0] >> 8) & 0xff) ||
    481		    LSB(ctx->remote_ip6[0], 2) != ((SRC_IP6[0] >> 16) & 0xff) ||
    482		    LSB(ctx->remote_ip6[0], 3) != ((SRC_IP6[0] >> 24) & 0xff) ||
    483		    LSB(ctx->remote_ip6[1], 0) != ((SRC_IP6[1] >> 0) & 0xff) ||
    484		    LSB(ctx->remote_ip6[1], 1) != ((SRC_IP6[1] >> 8) & 0xff) ||
    485		    LSB(ctx->remote_ip6[1], 2) != ((SRC_IP6[1] >> 16) & 0xff) ||
    486		    LSB(ctx->remote_ip6[1], 3) != ((SRC_IP6[1] >> 24) & 0xff) ||
    487		    LSB(ctx->remote_ip6[2], 0) != ((SRC_IP6[2] >> 0) & 0xff) ||
    488		    LSB(ctx->remote_ip6[2], 1) != ((SRC_IP6[2] >> 8) & 0xff) ||
    489		    LSB(ctx->remote_ip6[2], 2) != ((SRC_IP6[2] >> 16) & 0xff) ||
    490		    LSB(ctx->remote_ip6[2], 3) != ((SRC_IP6[2] >> 24) & 0xff) ||
    491		    LSB(ctx->remote_ip6[3], 0) != ((SRC_IP6[3] >> 0) & 0xff) ||
    492		    LSB(ctx->remote_ip6[3], 1) != ((SRC_IP6[3] >> 8) & 0xff) ||
    493		    LSB(ctx->remote_ip6[3], 2) != ((SRC_IP6[3] >> 16) & 0xff) ||
    494		    LSB(ctx->remote_ip6[3], 3) != ((SRC_IP6[3] >> 24) & 0xff))
    495			return SK_DROP;
    496		if (LSW(ctx->remote_ip6[0], 0) != ((SRC_IP6[0] >> 0) & 0xffff) ||
    497		    LSW(ctx->remote_ip6[0], 1) != ((SRC_IP6[0] >> 16) & 0xffff) ||
    498		    LSW(ctx->remote_ip6[1], 0) != ((SRC_IP6[1] >> 0) & 0xffff) ||
    499		    LSW(ctx->remote_ip6[1], 1) != ((SRC_IP6[1] >> 16) & 0xffff) ||
    500		    LSW(ctx->remote_ip6[2], 0) != ((SRC_IP6[2] >> 0) & 0xffff) ||
    501		    LSW(ctx->remote_ip6[2], 1) != ((SRC_IP6[2] >> 16) & 0xffff) ||
    502		    LSW(ctx->remote_ip6[3], 0) != ((SRC_IP6[3] >> 0) & 0xffff) ||
    503		    LSW(ctx->remote_ip6[3], 1) != ((SRC_IP6[3] >> 16) & 0xffff))
    504			return SK_DROP;
    505		/* Expect DST_IP6 in local_ip6 */
    506		if (LSB(ctx->local_ip6[0], 0) != ((DST_IP6[0] >> 0) & 0xff) ||
    507		    LSB(ctx->local_ip6[0], 1) != ((DST_IP6[0] >> 8) & 0xff) ||
    508		    LSB(ctx->local_ip6[0], 2) != ((DST_IP6[0] >> 16) & 0xff) ||
    509		    LSB(ctx->local_ip6[0], 3) != ((DST_IP6[0] >> 24) & 0xff) ||
    510		    LSB(ctx->local_ip6[1], 0) != ((DST_IP6[1] >> 0) & 0xff) ||
    511		    LSB(ctx->local_ip6[1], 1) != ((DST_IP6[1] >> 8) & 0xff) ||
    512		    LSB(ctx->local_ip6[1], 2) != ((DST_IP6[1] >> 16) & 0xff) ||
    513		    LSB(ctx->local_ip6[1], 3) != ((DST_IP6[1] >> 24) & 0xff) ||
    514		    LSB(ctx->local_ip6[2], 0) != ((DST_IP6[2] >> 0) & 0xff) ||
    515		    LSB(ctx->local_ip6[2], 1) != ((DST_IP6[2] >> 8) & 0xff) ||
    516		    LSB(ctx->local_ip6[2], 2) != ((DST_IP6[2] >> 16) & 0xff) ||
    517		    LSB(ctx->local_ip6[2], 3) != ((DST_IP6[2] >> 24) & 0xff) ||
    518		    LSB(ctx->local_ip6[3], 0) != ((DST_IP6[3] >> 0) & 0xff) ||
    519		    LSB(ctx->local_ip6[3], 1) != ((DST_IP6[3] >> 8) & 0xff) ||
    520		    LSB(ctx->local_ip6[3], 2) != ((DST_IP6[3] >> 16) & 0xff) ||
    521		    LSB(ctx->local_ip6[3], 3) != ((DST_IP6[3] >> 24) & 0xff))
    522			return SK_DROP;
    523		if (LSW(ctx->local_ip6[0], 0) != ((DST_IP6[0] >> 0) & 0xffff) ||
    524		    LSW(ctx->local_ip6[0], 1) != ((DST_IP6[0] >> 16) & 0xffff) ||
    525		    LSW(ctx->local_ip6[1], 0) != ((DST_IP6[1] >> 0) & 0xffff) ||
    526		    LSW(ctx->local_ip6[1], 1) != ((DST_IP6[1] >> 16) & 0xffff) ||
    527		    LSW(ctx->local_ip6[2], 0) != ((DST_IP6[2] >> 0) & 0xffff) ||
    528		    LSW(ctx->local_ip6[2], 1) != ((DST_IP6[2] >> 16) & 0xffff) ||
    529		    LSW(ctx->local_ip6[3], 0) != ((DST_IP6[3] >> 0) & 0xffff) ||
    530		    LSW(ctx->local_ip6[3], 1) != ((DST_IP6[3] >> 16) & 0xffff))
    531			return SK_DROP;
    532	} else {
    533		/* Expect :: IPs when family != AF_INET6 */
    534		if (LSB(ctx->remote_ip6[0], 0) != 0 || LSB(ctx->remote_ip6[0], 1) != 0 ||
    535		    LSB(ctx->remote_ip6[0], 2) != 0 || LSB(ctx->remote_ip6[0], 3) != 0 ||
    536		    LSB(ctx->remote_ip6[1], 0) != 0 || LSB(ctx->remote_ip6[1], 1) != 0 ||
    537		    LSB(ctx->remote_ip6[1], 2) != 0 || LSB(ctx->remote_ip6[1], 3) != 0 ||
    538		    LSB(ctx->remote_ip6[2], 0) != 0 || LSB(ctx->remote_ip6[2], 1) != 0 ||
    539		    LSB(ctx->remote_ip6[2], 2) != 0 || LSB(ctx->remote_ip6[2], 3) != 0 ||
    540		    LSB(ctx->remote_ip6[3], 0) != 0 || LSB(ctx->remote_ip6[3], 1) != 0 ||
    541		    LSB(ctx->remote_ip6[3], 2) != 0 || LSB(ctx->remote_ip6[3], 3) != 0)
    542			return SK_DROP;
    543		if (LSW(ctx->remote_ip6[0], 0) != 0 || LSW(ctx->remote_ip6[0], 1) != 0 ||
    544		    LSW(ctx->remote_ip6[1], 0) != 0 || LSW(ctx->remote_ip6[1], 1) != 0 ||
    545		    LSW(ctx->remote_ip6[2], 0) != 0 || LSW(ctx->remote_ip6[2], 1) != 0 ||
    546		    LSW(ctx->remote_ip6[3], 0) != 0 || LSW(ctx->remote_ip6[3], 1) != 0)
    547			return SK_DROP;
    548
    549		if (LSB(ctx->local_ip6[0], 0) != 0 || LSB(ctx->local_ip6[0], 1) != 0 ||
    550		    LSB(ctx->local_ip6[0], 2) != 0 || LSB(ctx->local_ip6[0], 3) != 0 ||
    551		    LSB(ctx->local_ip6[1], 0) != 0 || LSB(ctx->local_ip6[1], 1) != 0 ||
    552		    LSB(ctx->local_ip6[1], 2) != 0 || LSB(ctx->local_ip6[1], 3) != 0 ||
    553		    LSB(ctx->local_ip6[2], 0) != 0 || LSB(ctx->local_ip6[2], 1) != 0 ||
    554		    LSB(ctx->local_ip6[2], 2) != 0 || LSB(ctx->local_ip6[2], 3) != 0 ||
    555		    LSB(ctx->local_ip6[3], 0) != 0 || LSB(ctx->local_ip6[3], 1) != 0 ||
    556		    LSB(ctx->local_ip6[3], 2) != 0 || LSB(ctx->local_ip6[3], 3) != 0)
    557			return SK_DROP;
    558		if (LSW(ctx->remote_ip6[0], 0) != 0 || LSW(ctx->remote_ip6[0], 1) != 0 ||
    559		    LSW(ctx->remote_ip6[1], 0) != 0 || LSW(ctx->remote_ip6[1], 1) != 0 ||
    560		    LSW(ctx->remote_ip6[2], 0) != 0 || LSW(ctx->remote_ip6[2], 1) != 0 ||
    561		    LSW(ctx->remote_ip6[3], 0) != 0 || LSW(ctx->remote_ip6[3], 1) != 0)
    562			return SK_DROP;
    563	}
    564
    565	/* Success, redirect to KEY_SERVER_B */
    566	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
    567	if (sk) {
    568		bpf_sk_assign(ctx, sk, 0);
    569		bpf_sk_release(sk);
    570	}
    571	return SK_PASS;
    572}
    573
    574/* Check that sk_assign rejects SERVER_A socket with -ESOCKNOSUPPORT */
    575SEC("sk_lookup")
    576int sk_assign_esocknosupport(struct bpf_sk_lookup *ctx)
    577{
    578	struct bpf_sock *sk;
    579	int err, ret;
    580
    581	ret = SK_DROP;
    582	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    583	if (!sk)
    584		goto out;
    585
    586	err = bpf_sk_assign(ctx, sk, 0);
    587	if (err != -ESOCKTNOSUPPORT) {
    588		bpf_printk("sk_assign returned %d, expected %d\n",
    589			   err, -ESOCKTNOSUPPORT);
    590		goto out;
    591	}
    592
    593	ret = SK_PASS; /* Success, pass to regular lookup */
    594out:
    595	if (sk)
    596		bpf_sk_release(sk);
    597	return ret;
    598}
    599
    600SEC("sk_lookup")
    601int multi_prog_pass1(struct bpf_sk_lookup *ctx)
    602{
    603	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
    604	return SK_PASS;
    605}
    606
    607SEC("sk_lookup")
    608int multi_prog_pass2(struct bpf_sk_lookup *ctx)
    609{
    610	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
    611	return SK_PASS;
    612}
    613
    614SEC("sk_lookup")
    615int multi_prog_drop1(struct bpf_sk_lookup *ctx)
    616{
    617	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
    618	return SK_DROP;
    619}
    620
    621SEC("sk_lookup")
    622int multi_prog_drop2(struct bpf_sk_lookup *ctx)
    623{
    624	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
    625	return SK_DROP;
    626}
    627
    628static __always_inline int select_server_a(struct bpf_sk_lookup *ctx)
    629{
    630	struct bpf_sock *sk;
    631	int err;
    632
    633	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
    634	if (!sk)
    635		return SK_DROP;
    636
    637	err = bpf_sk_assign(ctx, sk, 0);
    638	bpf_sk_release(sk);
    639	if (err)
    640		return SK_DROP;
    641
    642	return SK_PASS;
    643}
    644
    645SEC("sk_lookup")
    646int multi_prog_redir1(struct bpf_sk_lookup *ctx)
    647{
    648	int ret;
    649
    650	ret = select_server_a(ctx);
    651	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
    652	return SK_PASS;
    653}
    654
    655SEC("sk_lookup")
    656int multi_prog_redir2(struct bpf_sk_lookup *ctx)
    657{
    658	int ret;
    659
    660	ret = select_server_a(ctx);
    661	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
    662	return SK_PASS;
    663}
    664
    665char _license[] SEC("license") = "Dual BSD/GPL";