|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | +/* |
| 3 | + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. |
| 4 | + */ |
| 5 | + |
| 6 | +#include "cgen/cgroup_sock_addr.h" |
| 7 | + |
| 8 | +#include <linux/bpf_common.h> |
| 9 | +#include <linux/if_ether.h> |
| 10 | + |
| 11 | +#include <assert.h> |
| 12 | +#include <errno.h> |
| 13 | +#include <stddef.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <bpfilter/flavor.h> |
| 17 | +#include <bpfilter/verdict.h> |
| 18 | + |
| 19 | +#include "cgen/program.h" |
| 20 | +#include "cgen/swich.h" |
| 21 | +#include "filter.h" |
| 22 | +#include "linux/bpf.h" |
| 23 | + |
| 24 | +// Forward definition to avoid headers clusterfuck. |
| 25 | +uint16_t htons(uint16_t hostshort); |
| 26 | + |
| 27 | +static int _bf_cgroup_sock_addr_gen_inline_prologue(struct bf_program *program) |
| 28 | +{ |
| 29 | + int r; |
| 30 | + |
| 31 | + assert(program); |
| 32 | + |
| 33 | + // The counters stub reads pkt_size unconditionally; zero it out. |
| 34 | + EMIT(program, BPF_ST_MEM(BPF_DW, BPF_REG_10, BF_PROG_CTX_OFF(pkt_size), 0)); |
| 35 | + |
| 36 | + /* Convert bpf_sock_addr.family to L3 protocol ID in R7, using the same |
| 37 | + * bf_swich pattern as cgroup_skb. */ |
| 38 | + EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
| 39 | + offsetof(struct bpf_sock_addr, family))); |
| 40 | + |
| 41 | + { |
| 42 | + _clean_bf_swich_ struct bf_swich swich = |
| 43 | + bf_swich_get(program, BPF_REG_2); |
| 44 | + |
| 45 | + EMIT_SWICH_OPTION(&swich, AF_INET, |
| 46 | + BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP))); |
| 47 | + EMIT_SWICH_OPTION(&swich, AF_INET6, |
| 48 | + BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6))); |
| 49 | + EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0)); |
| 50 | + |
| 51 | + r = bf_swich_generate(&swich); |
| 52 | + if (r) |
| 53 | + return r; |
| 54 | + } |
| 55 | + |
| 56 | + EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1, |
| 57 | + offsetof(struct bpf_sock_addr, protocol))); |
| 58 | + |
| 59 | + return 0; |
| 60 | +} |
| 61 | + |
| 62 | +static int _bf_cgroup_sock_addr_gen_inline_epilogue(struct bf_program *program) |
| 63 | +{ |
| 64 | + (void)program; |
| 65 | + |
| 66 | + return 0; |
| 67 | +} |
| 68 | + |
| 69 | +static int |
| 70 | +_bf_cgroup_sock_addr_gen_inline_matcher(struct bf_program *program, |
| 71 | + const struct bf_matcher *matcher) |
| 72 | +{ |
| 73 | + (void)program; |
| 74 | + (void)matcher; |
| 75 | + |
| 76 | + return -ENOTSUP; |
| 77 | +} |
| 78 | + |
| 79 | +/** |
| 80 | + * Convert a standard verdict into a return value. |
| 81 | + * |
| 82 | + * @param verdict Verdict to convert. Must be valid. |
| 83 | + * @return Cgroup return code corresponding to the verdict, as an integer. |
| 84 | + */ |
| 85 | +static int _bf_cgroup_sock_addr_get_verdict(enum bf_verdict verdict) |
| 86 | +{ |
| 87 | + switch (verdict) { |
| 88 | + case BF_VERDICT_ACCEPT: |
| 89 | + return 1; |
| 90 | + case BF_VERDICT_DROP: |
| 91 | + return 0; |
| 92 | + default: |
| 93 | + return -ENOTSUP; |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +const struct bf_flavor_ops bf_flavor_ops_cgroup_sock_addr = { |
| 98 | + .gen_inline_prologue = _bf_cgroup_sock_addr_gen_inline_prologue, |
| 99 | + .gen_inline_epilogue = _bf_cgroup_sock_addr_gen_inline_epilogue, |
| 100 | + .get_verdict = _bf_cgroup_sock_addr_get_verdict, |
| 101 | + .gen_inline_matcher = _bf_cgroup_sock_addr_gen_inline_matcher, |
| 102 | +}; |
0 commit comments