LCOV - code coverage report
Current view: top level - bpfilter/cgen - nf.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 46 0
Test Date: 2025-09-30 16:37:25 Functions: 0.0 % 4 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 "cgen/nf.h"
       7              : 
       8              : #include <linux/bpf.h>
       9              : #include <linux/bpf_common.h>
      10              : #include <linux/if_ether.h>
      11              : #include <linux/netfilter.h>
      12              : 
      13              : #include <stdbool.h>
      14              : #include <stddef.h>
      15              : #include <stdint.h>
      16              : #include <sys/socket.h>
      17              : 
      18              : #include <bpfilter/btf.h>
      19              : #include <bpfilter/flavor.h>
      20              : #include <bpfilter/helper.h>
      21              : #include <bpfilter/hook.h>
      22              : #include <bpfilter/verdict.h>
      23              : 
      24              : #include "cgen/jmp.h"
      25              : #include "cgen/program.h"
      26              : #include "cgen/stub.h"
      27              : #include "cgen/swich.h"
      28              : #include "filter.h"
      29              : 
      30              : #define BF_NF_PRIO_EVEN 2
      31              : #define BF_NF_PRIO_ODD 1
      32              : 
      33              : // Forward definition to avoid headers clusterfuck.
      34              : uint16_t htons(uint16_t hostshort);
      35              : 
      36              : static inline bool _bf_nf_hook_is_ingress(enum bf_hook hook)
      37              : {
      38            0 :     return hook == BF_HOOK_NF_PRE_ROUTING || hook == BF_HOOK_NF_LOCAL_IN ||
      39              :            hook == BF_HOOK_NF_FORWARD;
      40              : }
      41              : 
      42            0 : static int _bf_nf_gen_inline_prologue(struct bf_program *program)
      43              : {
      44              :     int r;
      45              :     int offset;
      46              : 
      47            0 :     bf_assert(program);
      48              : 
      49              :     // Copy the ifindex from to bpf_nf_ctx.state.{in,out}.ifindex the runtime context
      50            0 :     if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "state")) < 0)
      51              :         return offset;
      52            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
      53            0 :     if (_bf_nf_hook_is_ingress(program->runtime.chain->hook)) {
      54            0 :         if ((offset = bf_btf_get_field_off("nf_hook_state", "in")) < 0)
      55              :             return offset;
      56            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, offset));
      57              :     } else {
      58            0 :         if ((offset = bf_btf_get_field_off("nf_hook_state", "out")) < 0)
      59              :             return offset;
      60            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, offset));
      61              :     }
      62              : 
      63            0 :     if ((offset = bf_btf_get_field_off("net_device", "ifindex")) < 0)
      64              :         return offset;
      65            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_3, offset));
      66            0 :     EMIT(program,
      67              :          BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(ifindex)));
      68              : 
      69              :     /* BPF_PROG_TYPE_CGROUP_SKB doesn't provide access the the Ethernet header,
      70              :      * so we can't parse it and discover the L3 protocol ID.
      71              :      * Instead, we use the __sk_buff.family value and convert it to the
      72              :      * corresponding ethertype. */
      73            0 :     if ((offset = bf_btf_get_field_off("nf_hook_state", "pf")) < 0)
      74              :         return offset;
      75            0 :     EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_3, BPF_REG_2, offset));
      76              : 
      77              :     {
      78            0 :         _clean_bf_swich_ struct bf_swich swich =
      79            0 :             bf_swich_get(program, BPF_REG_3);
      80              : 
      81            0 :         EMIT_SWICH_OPTION(&swich, AF_INET,
      82              :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP)));
      83            0 :         EMIT_SWICH_OPTION(&swich, AF_INET6,
      84              :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6)));
      85            0 :         EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
      86              : 
      87            0 :         r = bf_swich_generate(&swich);
      88            0 :         if (r)
      89              :             return r;
      90              :     }
      91              : 
      92            0 :     EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset), 0));
      93              : 
      94              :     // Calculate the packet size (+ETH_HLEN) and store it into the runtime context
      95            0 :     if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
      96              :         return offset;
      97            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offset));
      98            0 :     if ((offset = bf_btf_get_field_off("sk_buff", "len")) < 0)
      99              :         return offset;
     100            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offset));
     101            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, ETH_HLEN));
     102            0 :     EMIT(program,
     103              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(pkt_size)));
     104              : 
     105            0 :     r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
     106            0 :     if (r)
     107              :         return r;
     108              : 
     109            0 :     r = bf_stub_parse_l3_hdr(program);
     110            0 :     if (r)
     111              :         return r;
     112              : 
     113            0 :     r = bf_stub_parse_l4_hdr(program);
     114              :     if (r)
     115              :         return r;
     116              : 
     117              :     return 0;
     118              : }
     119              : 
     120            0 : static int _bf_nf_gen_inline_epilogue(struct bf_program *program)
     121              : {
     122              :     UNUSED(program);
     123              : 
     124            0 :     return 0;
     125              : }
     126              : 
     127            0 : static int _bf_nf_gen_inline_get_mark(struct bf_program *program, int reg)
     128              : {
     129              :     int offset;
     130              : 
     131            0 :     EMIT(program,
     132              :          BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
     133            0 :     if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
     134              :         return offset;
     135            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
     136            0 :     if ((offset = bf_btf_get_field_off("sk_buff", "mark")) < 0)
     137              :         return offset;
     138            0 :     EMIT(program, BPF_LDX_MEM(BPF_W, reg, BPF_REG_2, offset));
     139              : 
     140            0 :     return 0;
     141              : }
     142              : 
     143              : /**
     144              :  * Convert a standard verdict into a return value.
     145              :  *
     146              :  * @param verdict Verdict to convert. Must be valid.
     147              :  * @return TC return code corresponding to the verdict, as an integer.
     148              :  */
     149            0 : static int _bf_nf_get_verdict(enum bf_verdict verdict)
     150              : {
     151            0 :     bf_assert(0 <= verdict && verdict < _BF_TERMINAL_VERDICT_MAX);
     152              : 
     153              :     static const int verdicts[] = {
     154              :         [BF_VERDICT_ACCEPT] = NF_ACCEPT,
     155              :         [BF_VERDICT_DROP] = NF_DROP,
     156              :     };
     157              : 
     158              :     static_assert(ARRAY_SIZE(verdicts) == _BF_TERMINAL_VERDICT_MAX);
     159              : 
     160            0 :     return verdicts[verdict];
     161              : }
     162              : 
     163              : const struct bf_flavor_ops bf_flavor_ops_nf = {
     164              :     .gen_inline_prologue = _bf_nf_gen_inline_prologue,
     165              :     .gen_inline_epilogue = _bf_nf_gen_inline_epilogue,
     166              :     .gen_inline_get_mark = _bf_nf_gen_inline_get_mark,
     167              :     .get_verdict = _bf_nf_get_verdict,
     168              : };
        

Generated by: LCOV version 2.0-1