LCOV - code coverage report
Current view: top level - bpfilter/cgen - nf.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 87.7 % 57 50
Test Date: 2026-03-13 09:17:53 Functions: 100.0 % 4 4
Branches: 48.6 % 74 36

             Branch data     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/matcher.h>
      23                 :             : #include <bpfilter/verdict.h>
      24                 :             : 
      25                 :             : #include "cgen/jmp.h"
      26                 :             : #include "cgen/matcher/meta.h"
      27                 :             : #include "cgen/matcher/packet.h"
      28                 :             : #include "cgen/program.h"
      29                 :             : #include "cgen/stub.h"
      30                 :             : #include "cgen/swich.h"
      31                 :             : #include "filter.h"
      32                 :             : 
      33                 :             : #define BF_NF_PRIO_EVEN 2
      34                 :             : #define BF_NF_PRIO_ODD 1
      35                 :             : 
      36                 :             : // Forward definition to avoid headers clusterfuck.
      37                 :             : uint16_t htons(uint16_t hostshort);
      38                 :             : 
      39                 :             : static inline bool _bf_nf_hook_is_ingress(enum bf_hook hook)
      40                 :             : {
      41                 :          16 :     return hook == BF_HOOK_NF_PRE_ROUTING || hook == BF_HOOK_NF_LOCAL_IN ||
      42                 :             :            hook == BF_HOOK_NF_FORWARD;
      43                 :             : }
      44                 :             : 
      45                 :          16 : static int _bf_nf_gen_inline_prologue(struct bf_program *program)
      46                 :             : {
      47                 :             :     int r;
      48                 :             :     int offset;
      49                 :             : 
      50                 :             :     assert(program);
      51                 :             : 
      52                 :             :     // Copy the ifindex from to bpf_nf_ctx.state.{in,out}.ifindex the runtime context
      53         [ +  - ]:          16 :     if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "state")) < 0)
      54                 :             :         return offset;
      55         [ -  + ]:          16 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
      56         [ +  + ]:          16 :     if (_bf_nf_hook_is_ingress(program->runtime.chain->hook)) {
      57         [ +  - ]:          14 :         if ((offset = bf_btf_get_field_off("nf_hook_state", "in")) < 0)
      58                 :             :             return offset;
      59         [ -  + ]:          14 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, offset));
      60                 :             :     } else {
      61         [ +  - ]:           2 :         if ((offset = bf_btf_get_field_off("nf_hook_state", "out")) < 0)
      62                 :             :             return offset;
      63         [ -  + ]:           2 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, offset));
      64                 :             :     }
      65                 :             : 
      66         [ +  - ]:          16 :     if ((offset = bf_btf_get_field_off("net_device", "ifindex")) < 0)
      67                 :             :         return offset;
      68         [ -  + ]:          16 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_3, offset));
      69         [ -  + ]:          16 :     EMIT(program,
      70                 :             :          BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(ifindex)));
      71                 :             : 
      72                 :             :     /* BPF_PROG_TYPE_CGROUP_SKB doesn't provide access the the Ethernet header,
      73                 :             :      * so we can't parse it and discover the L3 protocol ID.
      74                 :             :      * Instead, we use the __sk_buff.family value and convert it to the
      75                 :             :      * corresponding ethertype. */
      76         [ +  - ]:          16 :     if ((offset = bf_btf_get_field_off("nf_hook_state", "pf")) < 0)
      77                 :             :         return offset;
      78         [ -  + ]:          16 :     EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_3, BPF_REG_2, offset));
      79                 :             : 
      80                 :             :     {
      81                 :          16 :         _clean_bf_swich_ struct bf_swich swich =
      82         [ -  + ]:          16 :             bf_swich_get(program, BPF_REG_3);
      83                 :             : 
      84         [ -  + ]:          16 :         EMIT_SWICH_OPTION(&swich, AF_INET,
      85                 :             :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP)));
      86         [ -  + ]:          16 :         EMIT_SWICH_OPTION(&swich, AF_INET6,
      87                 :             :                           BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6)));
      88         [ -  + ]:          16 :         EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
      89                 :             : 
      90                 :          16 :         r = bf_swich_generate(&swich);
      91         [ +  - ]:          16 :         if (r)
      92                 :             :             return r;
      93                 :             :     }
      94                 :             : 
      95         [ -  + ]:          16 :     EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset), 0));
      96                 :             : 
      97                 :             :     // Calculate the packet size (+ETH_HLEN) and store it into the runtime context
      98         [ +  - ]:          16 :     if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
      99                 :             :         return offset;
     100         [ -  + ]:          16 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offset));
     101         [ +  - ]:          16 :     if ((offset = bf_btf_get_field_off("sk_buff", "len")) < 0)
     102                 :             :         return offset;
     103         [ -  + ]:          16 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offset));
     104         [ -  + ]:          16 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, ETH_HLEN));
     105         [ -  + ]:          16 :     EMIT(program,
     106                 :             :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(pkt_size)));
     107                 :             : 
     108                 :          16 :     r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
     109         [ +  - ]:          16 :     if (r)
     110                 :             :         return r;
     111                 :             : 
     112                 :          16 :     r = bf_stub_parse_l3_hdr(program);
     113         [ +  - ]:          16 :     if (r)
     114                 :             :         return r;
     115                 :             : 
     116                 :          16 :     r = bf_stub_parse_l4_hdr(program);
     117                 :             :     if (r)
     118                 :             :         return r;
     119                 :             : 
     120                 :             :     return 0;
     121                 :             : }
     122                 :             : 
     123                 :          15 : static int _bf_nf_gen_inline_epilogue(struct bf_program *program)
     124                 :             : {
     125                 :             :     (void)program;
     126                 :             : 
     127                 :          15 :     return 0;
     128                 :             : }
     129                 :             : 
     130                 :         709 : static int _bf_nf_gen_inline_matcher(struct bf_program *program,
     131                 :             :                                      const struct bf_matcher *matcher)
     132                 :             : {
     133                 :             :     int offset;
     134                 :             : 
     135                 :             :     assert(program);
     136                 :             :     assert(matcher);
     137                 :             : 
     138      [ +  -  + ]:         709 :     switch (bf_matcher_get_type(matcher)) {
     139                 :          10 :     case BF_MATCHER_META_MARK:
     140         [ -  + ]:          10 :         EMIT(program,
     141                 :             :              BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
     142         [ +  - ]:          10 :         if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
     143                 :             :             return offset;
     144         [ -  + ]:          10 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, offset));
     145         [ +  - ]:          10 :         if ((offset = bf_btf_get_field_off("sk_buff", "mark")) < 0)
     146                 :             :             return offset;
     147         [ -  + ]:          10 :         EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_2, offset));
     148                 :             : 
     149                 :          10 :         return bf_matcher_generate_meta_mark_cmp(program, matcher);
     150                 :           0 :     case BF_MATCHER_META_FLOW_HASH:
     151         [ #  # ]:           0 :         EMIT(program,
     152                 :             :              BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
     153         [ #  # ]:           0 :         if ((offset = bf_btf_get_field_off("bpf_nf_ctx", "skb")) < 0)
     154                 :             :             return offset;
     155         [ #  # ]:           0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offset));
     156                 :             : 
     157                 :           0 :         return bf_matcher_generate_meta_flow_hash_cmp(program, matcher);
     158                 :         699 :     default:
     159                 :         699 :         return bf_matcher_generate_packet(program, matcher);
     160                 :             :     }
     161                 :             : }
     162                 :             : 
     163                 :             : /**
     164                 :             :  * Convert a standard verdict into a return value.
     165                 :             :  *
     166                 :             :  * @param verdict Verdict to convert. Must be valid.
     167                 :             :  * @return Netfilter return code corresponding to the verdict, as an integer.
     168                 :             :  */
     169                 :         186 : static int _bf_nf_get_verdict(enum bf_verdict verdict)
     170                 :             : {
     171      [ +  -  + ]:         186 :     switch (verdict) {
     172                 :             :     case BF_VERDICT_ACCEPT:
     173                 :             :         return NF_ACCEPT;
     174                 :           3 :     case BF_VERDICT_DROP:
     175                 :           3 :         return NF_DROP;
     176                 :           0 :     default:
     177                 :           0 :         return -ENOTSUP;
     178                 :             :     }
     179                 :             : }
     180                 :             : 
     181                 :             : const struct bf_flavor_ops bf_flavor_ops_nf = {
     182                 :             :     .gen_inline_prologue = _bf_nf_gen_inline_prologue,
     183                 :             :     .gen_inline_epilogue = _bf_nf_gen_inline_epilogue,
     184                 :             :     .get_verdict = _bf_nf_get_verdict,
     185                 :             :     .gen_inline_matcher = _bf_nf_gen_inline_matcher,
     186                 :             : };
        

Generated by: LCOV version 2.0-1