LCOV - code coverage report
Current view: top level - bpfilter/cgen/matcher - meta.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 60 0
Test Date: 2025-09-16 14:46:44 Functions: 0.0 % 6 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "cgen/matcher/meta.h"
       7              : 
       8              : #include <linux/bpf.h>
       9              : #include <linux/bpf_common.h>
      10              : #include <linux/in.h> // NOLINT
      11              : #include <linux/tcp.h>
      12              : #include <linux/udp.h>
      13              : 
      14              : #include <endian.h>
      15              : #include <errno.h>
      16              : #include <stddef.h>
      17              : #include <stdint.h>
      18              : 
      19              : #include <bpfilter/logger.h>
      20              : #include <bpfilter/matcher.h>
      21              : 
      22              : #include "cgen/program.h"
      23              : #include "cgen/swich.h"
      24              : #include "filter.h"
      25              : 
      26              : /** @todo Add support for input and output interface filtering based on the
      27              :  * program's hook. */
      28            0 : static int _bf_matcher_generate_meta_iface(struct bf_program *program,
      29              :                                            const struct bf_matcher *matcher)
      30              : {
      31            0 :     EMIT(program,
      32              :          BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_10, BF_PROG_CTX_OFF(ifindex)));
      33            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
      34              :         program, BPF_JMP_IMM(BPF_JNE, BPF_REG_1,
      35              :                              *(uint32_t *)bf_matcher_payload(matcher), 0));
      36              : 
      37            0 :     return 0;
      38              : }
      39              : 
      40            0 : static int _bf_matcher_generate_meta_l3_proto(struct bf_program *program,
      41              :                                               const struct bf_matcher *matcher)
      42              : {
      43            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
      44              :         program,
      45              :         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
      46              :                     htobe16(*(uint16_t *)bf_matcher_payload(matcher)), 0));
      47              : 
      48            0 :     return 0;
      49              : }
      50              : 
      51            0 : static int _bf_matcher_generate_meta_l4_proto(struct bf_program *program,
      52              :                                               const struct bf_matcher *matcher)
      53              : {
      54            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
      55              :         program,
      56              :         BPF_JMP_IMM(bf_matcher_get_op(matcher) == BF_MATCHER_EQ ? BPF_JNE :
      57              :                                                                   BPF_JEQ,
      58              :                     BPF_REG_8, *(uint8_t *)bf_matcher_payload(matcher), 0));
      59              : 
      60            0 :     return 0;
      61              : }
      62              : 
      63              : static int
      64            0 : _bf_matcher_generate_meta_probability(struct bf_program *program,
      65              :                                       const struct bf_matcher *matcher)
      66              : {
      67            0 :     uint8_t proba = *(uint8_t *)bf_matcher_payload(matcher);
      68              : 
      69            0 :     EMIT(program, BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32));
      70            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
      71              :         program,
      72              :         BPF_JMP_IMM(BPF_JGT, BPF_REG_0,
      73              :                     (uint32_t)((uint64_t)UINT32_MAX * (proba / 100.0)), 0));
      74              : 
      75            0 :     return 0;
      76              : }
      77              : 
      78            0 : static int _bf_matcher_generate_meta_port(struct bf_program *program,
      79              :                                           const struct bf_matcher *matcher)
      80              : {
      81            0 :     _clean_bf_swich_ struct bf_swich swich;
      82            0 :     uint16_t *port = (uint16_t *)bf_matcher_payload(matcher);
      83              :     int r;
      84              : 
      85              :     // Load L4 header address into r6
      86            0 :     EMIT(program,
      87              :          BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
      88              : 
      89              :     // Get the packet's port into r1
      90            0 :     swich = bf_swich_get(program, BPF_REG_8);
      91            0 :     EMIT_SWICH_OPTION(
      92              :         &swich, IPPROTO_TCP,
      93              :         BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6,
      94              :                     bf_matcher_get_type(matcher) == BF_MATCHER_META_SPORT ?
      95              :                         offsetof(struct tcphdr, source) :
      96              :                         offsetof(struct tcphdr, dest)));
      97            0 :     EMIT_SWICH_OPTION(
      98              :         &swich, IPPROTO_UDP,
      99              :         BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6,
     100              :                     bf_matcher_get_type(matcher) == BF_MATCHER_META_SPORT ?
     101              :                         offsetof(struct udphdr, source) :
     102              :                         offsetof(struct udphdr, dest)));
     103            0 :     EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_1, 0));
     104              : 
     105            0 :     r = bf_swich_generate(&swich);
     106            0 :     if (r)
     107            0 :         return bf_err_r(r, "failed to generate swich for meta.(s|d)port");
     108              : 
     109              :     // If r1 == 0: no TCP nor UDP header found, jump to the next rule
     110            0 :     EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0));
     111              : 
     112            0 :     switch (bf_matcher_get_op(matcher)) {
     113            0 :     case BF_MATCHER_EQ:
     114            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     115              :                                  BPF_JMP_IMM(BPF_JNE, BPF_REG_1, *port, 0));
     116            0 :         break;
     117            0 :     case BF_MATCHER_NE:
     118            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     119              :                                  BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, *port, 0));
     120            0 :         break;
     121            0 :     case BF_MATCHER_RANGE:
     122              :         /* Convert the big-endian value stored in the packet into a
     123              :          * little-endian value for x86 and arm before comparing it to the
     124              :          * reference value. This is a JLT/JGT comparison, we need to have the
     125              :          * MSB where the machine expects then. */
     126            0 :         EMIT(program, BPF_BSWAP(BPF_REG_1, 16));
     127            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     128              :                                  BPF_JMP_IMM(BPF_JLT, BPF_REG_1, port[0], 0));
     129            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     130              :                                  BPF_JMP_IMM(BPF_JGT, BPF_REG_1, port[1], 0));
     131            0 :         break;
     132            0 :     default:
     133            0 :         return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)",
     134              :                         bf_matcher_op_to_str(bf_matcher_get_op(matcher)),
     135              :                         bf_matcher_get_op(matcher));
     136              :     }
     137              : 
     138              :     return 0;
     139              : }
     140              : 
     141            0 : int bf_matcher_generate_meta(struct bf_program *program,
     142              :                              const struct bf_matcher *matcher)
     143              : {
     144              :     int r;
     145              : 
     146            0 :     switch (bf_matcher_get_type(matcher)) {
     147            0 :     case BF_MATCHER_META_IFACE:
     148            0 :         r = _bf_matcher_generate_meta_iface(program, matcher);
     149            0 :         break;
     150            0 :     case BF_MATCHER_META_L3_PROTO:
     151            0 :         r = _bf_matcher_generate_meta_l3_proto(program, matcher);
     152            0 :         break;
     153            0 :     case BF_MATCHER_META_L4_PROTO:
     154            0 :         r = _bf_matcher_generate_meta_l4_proto(program, matcher);
     155            0 :         break;
     156            0 :     case BF_MATCHER_META_PROBABILITY:
     157            0 :         r = _bf_matcher_generate_meta_probability(program, matcher);
     158            0 :         break;
     159            0 :     case BF_MATCHER_META_SPORT:
     160              :     case BF_MATCHER_META_DPORT:
     161            0 :         r = _bf_matcher_generate_meta_port(program, matcher);
     162            0 :         break;
     163            0 :     default:
     164            0 :         return bf_err_r(-EINVAL, "unknown matcher type %d",
     165              :                         bf_matcher_get_type(matcher));
     166              :     };
     167              : 
     168              :     if (r)
     169              :         return r;
     170              : 
     171              :     return 0;
     172              : }
        

Generated by: LCOV version 2.0-1