LCOV - code coverage report
Current view: top level - bpfilter/cgen - cgroup.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 48 0
Test Date: 2025-02-26 17:59:59 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/cgen/cgroup.h"
       7              : 
       8              : #include <linux/bpf_common.h>
       9              : #include <linux/if_ether.h>
      10              : 
      11              : #include <stddef.h>
      12              : #include <stdint.h>
      13              : #include <sys/socket.h>
      14              : 
      15              : #include "bpfilter/cgen/cgen.h"
      16              : #include "bpfilter/cgen/prog/link.h"
      17              : #include "bpfilter/cgen/program.h"
      18              : #include "bpfilter/cgen/stub.h"
      19              : #include "bpfilter/cgen/swich.h"
      20              : #include "core/btf.h"
      21              : #include "core/flavor.h"
      22              : #include "core/helper.h"
      23              : #include "core/hook.h"
      24              : #include "core/list.h"
      25              : #include "core/logger.h"
      26              : #include "core/verdict.h"
      27              : #include "linux/bpf.h"
      28              : 
      29              : #include "external/filter.h"
      30              : 
      31              : static int _bf_cgroup_gen_inline_prologue(struct bf_program *program);
      32              : static int _bf_cgroup_gen_inline_epilogue(struct bf_program *program);
      33              : static int _bf_cgroup_get_verdict(enum bf_verdict verdict);
      34              : static int _bf_cgroup_attach_prog(
      35              :     struct bf_program *new_prog, struct bf_program *old_prog,
      36              :     int (*get_new_link_cb)(struct bf_program *prog, struct bf_link *old_link,
      37              :                            struct bf_link **new_link));
      38              : static int _bf_cgroup_detach_prog(struct bf_program *program);
      39              : 
      40              : const struct bf_flavor_ops bf_flavor_ops_cgroup = {
      41              :     .gen_inline_prologue = _bf_cgroup_gen_inline_prologue,
      42              :     .gen_inline_epilogue = _bf_cgroup_gen_inline_epilogue,
      43              :     .get_verdict = _bf_cgroup_get_verdict,
      44              :     .attach_prog = _bf_cgroup_attach_prog,
      45              :     .detach_prog = _bf_cgroup_detach_prog,
      46              : };
      47              : 
      48              : // Forward definition to avoid headers clusterfuck.
      49              : uint16_t htons(uint16_t hostshort);
      50              : 
      51            0 : static int _bf_cgroup_gen_inline_prologue(struct bf_program *program)
      52              : {
      53              :     int offset;
      54              :     int r;
      55              : 
      56            0 :     bf_assert(program);
      57              : 
      58              :     // Calculate the packet size (+ETH_HLEN) and store it into the runtime context
      59            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
      60              :                               offsetof(struct __sk_buff, data)));
      61            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
      62              :                               offsetof(struct __sk_buff, data_end)));
      63            0 :     EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2));
      64            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ETH_HLEN));
      65            0 :     EMIT(program,
      66              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
      67              : 
      68              :     /** The @c __sk_buff structure contains two fields related to the interface
      69              :      * index: @c ingress_ifindex and @c ifindex . @c ingress_ifindex is the
      70              :      * interface index the packet has been received on. However, we use
      71              :      * @c ifindex which is the interface index the packet is processed by: if
      72              :      * a packet is redirected locally from interface #1 to interface #2, then
      73              :      * @c ingress_ifindex will contain @c 1 but @c ifindex will contains @c 2 .
      74              :      * For egress, only @c ifindex is used.
      75              :      */
      76            0 :     if ((r = bf_btf_get_field_off("__sk_buff", "ifindex")) < 0)
      77              :         return r;
      78            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, r));
      79            0 :     EMIT(program,
      80              :          BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
      81              : 
      82              :     /* BPF_PROG_TYPE_CGROUP_SKB doesn't provide access the the Ethernet header,
      83              :      * so we can't parse it and discover the L3 protocol ID.
      84              :      * Instead, we use the __sk_buff.family value and convert it to the
      85              :      * corresponding ethertype. */
      86            0 :     if ((offset = bf_btf_get_field_off("__sk_buff", "family")) < 0)
      87              :         return offset;
      88            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offset));
      89              : 
      90              :     {
      91            0 :         _cleanup_bf_swich_ struct bf_swich swich =
      92            0 :             bf_swich_get(program, BPF_REG_2);
      93              : 
      94            0 :         EMIT_SWICH_OPTION(&swich, AF_INET,
      95              :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP)));
      96            0 :         EMIT_SWICH_OPTION(&swich, AF_INET6,
      97              :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6)));
      98            0 :         EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
      99              : 
     100            0 :         r = bf_swich_generate(&swich);
     101            0 :         if (r)
     102              :             return r;
     103              :     }
     104              : 
     105            0 :     EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset), 0));
     106              : 
     107            0 :     r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
     108            0 :     if (r)
     109              :         return r;
     110              : 
     111            0 :     r = bf_stub_parse_l3_hdr(program);
     112            0 :     if (r)
     113              :         return r;
     114              : 
     115            0 :     r = bf_stub_parse_l4_hdr(program);
     116              :     if (r)
     117              :         return r;
     118              : 
     119              :     return 0;
     120              : }
     121              : 
     122            0 : static int _bf_cgroup_gen_inline_epilogue(struct bf_program *program)
     123              : {
     124              :     UNUSED(program);
     125              : 
     126            0 :     return 0;
     127              : }
     128              : 
     129              : /**
     130              :  * Convert a standard verdict into a return value.
     131              :  *
     132              :  * @param verdict Verdict to convert. Must be valid.
     133              :  * @return TC return code corresponding to the verdict, as an integer.
     134              :  */
     135            0 : static int _bf_cgroup_get_verdict(enum bf_verdict verdict)
     136              : {
     137            0 :     bf_assert(0 <= verdict && verdict < _BF_TERMINAL_VERDICT_MAX);
     138              : 
     139              :     static const int verdicts[] = {
     140              :         [BF_VERDICT_ACCEPT] = 1,
     141              :         [BF_VERDICT_DROP] = 0,
     142              :     };
     143              : 
     144              :     static_assert(ARRAY_SIZE(verdicts) == _BF_TERMINAL_VERDICT_MAX);
     145              : 
     146            0 :     return verdicts[verdict];
     147              : }
     148              : 
     149            0 : static int _bf_cgroup_attach_prog(
     150              :     struct bf_program *new_prog, struct bf_program *old_prog,
     151              :     int (*get_new_link_cb)(struct bf_program *prog, struct bf_link *old_link,
     152              :                            struct bf_link **new_link))
     153              : {
     154              :     struct bf_link *new_link;
     155              :     struct bf_link *old_link;
     156              :     int new_fd;
     157              :     const char *cgroup_path;
     158              :     int r;
     159              : 
     160            0 :     bf_assert(new_prog && get_new_link_cb);
     161              : 
     162            0 :     old_link = old_prog ? bf_list_get_at(&old_prog->links, 0) : NULL;
     163            0 :     new_fd = new_prog->runtime.prog_fd;
     164            0 :     cgroup_path = new_prog->runtime.chain->hook_opts.cgroup;
     165              : 
     166            0 :     r = get_new_link_cb(new_prog, old_link, &new_link);
     167            0 :     if (r)
     168            0 :         return bf_err_r(r, "failed to create new cgroup link");
     169              : 
     170            0 :     if (old_link) {
     171            0 :         r = bf_link_update(new_link, new_fd);
     172            0 :         if (r) {
     173            0 :             return bf_err_r(
     174              :                 r, "failed to update existing link for cgroup bf_program");
     175              :         }
     176              :     } else {
     177            0 :         r = bf_link_attach_cgroup(new_link, new_fd, cgroup_path);
     178            0 :         if (r)
     179            0 :             return bf_err_r(r, "failed to attach cgroup program");
     180              :     }
     181              : 
     182              :     return 0;
     183              : }
     184              : 
     185              : /**
     186              :  * Detach the cgroup BPF program.
     187              :  *
     188              :  * @param program Attached cgroup BPF program. Can't be NULL.
     189              :  * @return 0 on success, negative errno value on failure.
     190              :  */
     191            0 : static int _bf_cgroup_detach_prog(struct bf_program *program)
     192              : {
     193            0 :     bf_assert(program);
     194              : 
     195            0 :     return bf_link_detach(bf_list_get_at(&program->links, 0));
     196              : }
        

Generated by: LCOV version 2.0-1