LCOV - code coverage report
Current view: top level - libbpfilter/cgen - tc.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 100.0 % 51 51
Test Date: 2026-04-17 15:45:04 Functions: 100.0 % 6 6
Branches: 58.1 % 43 25

             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/tc.h"
       7                 :             : 
       8                 :             : #include <linux/bpf.h>
       9                 :             : #include <linux/bpf_common.h>
      10                 :             : #include <linux/pkt_cls.h>
      11                 :             : 
      12                 :             : #include <stddef.h>
      13                 :             : #include <stdint.h>
      14                 :             : 
      15                 :             : #include <bpfilter/btf.h>
      16                 :             : #include <bpfilter/flavor.h>
      17                 :             : #include <bpfilter/helper.h>
      18                 :             : #include <bpfilter/matcher.h>
      19                 :             : #include <bpfilter/verdict.h>
      20                 :             : 
      21                 :             : #include "cgen/matcher/cmp.h"
      22                 :             : #include "cgen/packet.h"
      23                 :             : #include "cgen/program.h"
      24                 :             : #include "cgen/stub.h"
      25                 :             : #include "filter.h"
      26                 :             : 
      27                 :         244 : static int _bf_tc_gen_inline_prologue(struct bf_program *program)
      28                 :             : {
      29                 :             :     int r;
      30                 :             : 
      31                 :             :     assert(program);
      32                 :             : 
      33                 :             :     // Copy the packet size into the runtime context
      34         [ +  - ]:         244 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
      35                 :             :                               offsetof(struct __sk_buff, len)));
      36         [ +  - ]:         244 :     EMIT(program,
      37                 :             :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
      38                 :             : 
      39                 :             :     /** The @c __sk_buff structure contains two fields related to the interface
      40                 :             :      * index: @c ingress_ifindex and @c ifindex . @c ingress_ifindex is the
      41                 :             :      * interface index the packet has been received on. However, we use
      42                 :             :      * @c ifindex which is the interface index the packet is processed by: if
      43                 :             :      * a packet is redirected locally from interface #1 to interface #2, then
      44                 :             :      * @c ingress_ifindex will contain @c 1 but @c ifindex will contains @c 2 .
      45                 :             :      * For egress, only @c ifindex is used.
      46                 :             :      */
      47         [ +  - ]:         244 :     if ((r = bf_btf_get_field_off("__sk_buff", "ifindex")) < 0)
      48                 :             :         return r;
      49         [ +  - ]:         244 :     EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, r));
      50         [ +  - ]:         244 :     EMIT(program,
      51                 :             :          BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
      52                 :             : 
      53                 :         244 :     r = bf_stub_make_ctx_skb_dynptr(program, BPF_REG_1);
      54         [ +  - ]:         244 :     if (r)
      55                 :             :         return r;
      56                 :             : 
      57                 :         244 :     r = bf_stub_parse_l2_ethhdr(program);
      58         [ +  - ]:         244 :     if (r)
      59                 :             :         return r;
      60                 :             : 
      61                 :         244 :     r = bf_stub_parse_l3_hdr(program);
      62         [ +  - ]:         244 :     if (r)
      63                 :             :         return r;
      64                 :             : 
      65                 :         244 :     r = bf_stub_parse_l4_hdr(program);
      66                 :             :     if (r)
      67                 :             :         return r;
      68                 :             : 
      69                 :             :     return 0;
      70                 :             : }
      71                 :             : 
      72                 :         244 : static int _bf_tc_gen_inline_epilogue(struct bf_program *program)
      73                 :             : {
      74                 :             :     (void)program;
      75                 :             : 
      76                 :         244 :     return 0;
      77                 :             : }
      78                 :             : 
      79                 :           6 : static int _bf_tc_gen_inline_set_mark(struct bf_program *program, uint32_t mark)
      80                 :             : {
      81         [ +  - ]:           6 :     EMIT(program,
      82                 :             :          BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
      83         [ +  - ]:           6 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_2, mark));
      84                 :           6 :     EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_2,
      85                 :             :                               offsetof(struct __sk_buff, mark)));
      86                 :             : 
      87                 :             :     return 0;
      88                 :             : }
      89                 :             : 
      90                 :         551 : static int _bf_tc_gen_inline_matcher(struct bf_program *program,
      91                 :             :                                      const struct bf_matcher *matcher)
      92                 :             : {
      93                 :             :     assert(program);
      94                 :             :     assert(matcher);
      95                 :             : 
      96      [ +  +  + ]:         551 :     switch (bf_matcher_get_type(matcher)) {
      97                 :          12 :     case BF_MATCHER_META_MARK:
      98         [ +  - ]:          12 :         EMIT(program,
      99                 :             :              BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
     100         [ +  - ]:          12 :         EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
     101                 :             :                                   offsetof(struct __sk_buff, mark)));
     102                 :             : 
     103                 :          12 :         return bf_cmp_value(program, bf_matcher_get_op(matcher),
     104                 :             :                             bf_matcher_payload(matcher), 4, BPF_REG_1);
     105                 :          36 :     case BF_MATCHER_META_FLOW_HASH:
     106         [ +  - ]:          36 :         EMIT(program,
     107                 :             :              BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(arg)));
     108         [ +  - ]:          36 :         EMIT(program, BPF_EMIT_CALL(BPF_FUNC_get_hash_recalc));
     109                 :             : 
     110         [ +  + ]:          36 :         if (bf_matcher_get_op(matcher) == BF_MATCHER_RANGE) {
     111                 :          16 :             uint32_t *hash = (uint32_t *)bf_matcher_payload(matcher);
     112                 :          16 :             return bf_cmp_range(program, hash[0], hash[1], BPF_REG_0);
     113                 :             :         }
     114                 :             : 
     115                 :          20 :         return bf_cmp_value(program, bf_matcher_get_op(matcher),
     116                 :             :                             bf_matcher_payload(matcher), 4, BPF_REG_0);
     117                 :         503 :     default:
     118                 :         503 :         return bf_packet_gen_inline_matcher(program, matcher);
     119                 :             :     }
     120                 :             : }
     121                 :             : 
     122                 :             : /**
     123                 :             :  * @brief Generate bytecode to redirect a packet using TC.
     124                 :             :  *
     125                 :             :  * TC redirect supports both ingress and egress directions via the
     126                 :             :  * BPF_F_INGRESS flag passed to bpf_redirect().
     127                 :             :  *
     128                 :             :  * @param program Program to generate bytecode for. Can't be NULL.
     129                 :             :  * @param ifindex Target interface index.
     130                 :             :  * @param dir Direction: ingress or egress.
     131                 :             :  * @return 0 on success, or a negative errno value on failure.
     132                 :             :  */
     133                 :           6 : static int _bf_tc_gen_inline_redirect(struct bf_program *program,
     134                 :             :                                       uint32_t ifindex,
     135                 :             :                                       enum bf_redirect_dir dir)
     136                 :             : {
     137                 :           6 :     uint64_t flags = dir == BF_REDIRECT_INGRESS ? BPF_F_INGRESS : 0;
     138                 :             : 
     139                 :             :     assert(program);
     140                 :             : 
     141                 :             :     // bpf_redirect(ifindex, flags)
     142         [ +  - ]:           6 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_1, ifindex));
     143         [ +  - ]:           6 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_2, flags));
     144         [ +  - ]:           6 :     EMIT(program, BPF_EMIT_CALL(BPF_FUNC_redirect));
     145                 :             : 
     146                 :             :     // Return value from bpf_redirect() is TC_ACT_REDIRECT on success
     147                 :           6 :     EMIT(program, BPF_EXIT_INSN());
     148                 :             : 
     149                 :             :     return 0;
     150                 :             : }
     151                 :             : 
     152                 :             : /**
     153                 :             :  * Convert a standard verdict into a return value.
     154                 :             :  *
     155                 :             :  * @param verdict Verdict to convert. Must be valid.
     156                 :             :  * @param ret_code TC return code. Can't be NULL.
     157                 :             :  * @return 0 on success, or a negative errno value on failure.
     158                 :             :  */
     159                 :        1504 : static int _bf_tc_get_verdict(enum bf_verdict verdict, int *ret_code)
     160                 :             : {
     161                 :             :     assert(ret_code);
     162                 :             : 
     163   [ +  +  +  - ]:        1504 :     switch (verdict) {
     164                 :        1267 :     case BF_VERDICT_ACCEPT:
     165                 :        1267 :         *ret_code = TCX_PASS;
     166                 :        1267 :         return 0;
     167                 :         227 :     case BF_VERDICT_DROP:
     168                 :         227 :         *ret_code = TCX_DROP;
     169                 :         227 :         return 0;
     170                 :          10 :     case BF_VERDICT_NEXT:
     171                 :          10 :         *ret_code = TCX_NEXT;
     172                 :          10 :         return 0;
     173                 :             :     default:
     174                 :             :         return -ENOTSUP;
     175                 :             :     }
     176                 :             : }
     177                 :             : 
     178                 :             : const struct bf_flavor_ops bf_flavor_ops_tc = {
     179                 :             :     .gen_inline_prologue = _bf_tc_gen_inline_prologue,
     180                 :             :     .gen_inline_epilogue = _bf_tc_gen_inline_epilogue,
     181                 :             :     .gen_inline_set_mark = _bf_tc_gen_inline_set_mark,
     182                 :             :     .gen_inline_redirect = _bf_tc_gen_inline_redirect,
     183                 :             :     .get_verdict = _bf_tc_get_verdict,
     184                 :             :     .gen_inline_matcher = _bf_tc_gen_inline_matcher,
     185                 :             :     .gen_inline_log = bf_packet_gen_inline_log,
     186                 :             : };
        

Generated by: LCOV version 2.0-1