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