LCOV - code coverage report
Current view: top level - bpfilter/cgen/matcher - ip6.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 75 0
Test Date: 2025-06-20 13:16:12 Functions: 0.0 % 3 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 "bpfilter/cgen/matcher/ip6.h"
       7              : 
       8              : #include <linux/bpf.h>
       9              : #include <linux/bpf_common.h>
      10              : #include <linux/if_ether.h>
      11              : #include <linux/ipv6.h>
      12              : 
      13              : #include <endian.h>
      14              : #include <errno.h>
      15              : #include <stddef.h>
      16              : #include <stdint.h>
      17              : 
      18              : #include "bpfilter/cgen/jmp.h"
      19              : #include "bpfilter/cgen/program.h"
      20              : #include "core/logger.h"
      21              : #include "core/matcher.h"
      22              : #include "core/set.h"
      23              : 
      24              : #include "external/filter.h"
      25              : 
      26              : #define _bf_make32(a, b, c, d)                                                 \
      27              :     (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) |    \
      28              :      (uint32_t)(d))
      29              : #define _BF_MASK_LAST_BYTE 15
      30              : 
      31            0 : static int _bf_matcher_generate_ip6_addr(struct bf_program *program,
      32              :                                          const struct bf_matcher *matcher)
      33              : {
      34              :     struct bf_jmpctx j0, j1;
      35              :     struct bf_matcher_ip6_addr *addr = (void *)&matcher->payload;
      36            0 :     size_t offset = matcher->type == BF_MATCHER_IP6_SADDR ?
      37            0 :                         offsetof(struct ipv6hdr, saddr) :
      38              :                         offsetof(struct ipv6hdr, daddr);
      39              : 
      40            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
      41            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
      42              : 
      43            0 :     if (addr->mask[_BF_MASK_LAST_BYTE] != (uint8_t)~0) {
      44            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
      45              :                                     _bf_make32(addr->mask[7], addr->mask[6],
      46              :                                                addr->mask[5], addr->mask[4])));
      47            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      48            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
      49              :                                     _bf_make32(addr->mask[3], addr->mask[2],
      50              :                                                addr->mask[1], addr->mask[0])));
      51            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      52            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
      53              : 
      54            0 :         EMIT(program,
      55              :              BPF_MOV32_IMM(BPF_REG_3,
      56              :                            _bf_make32(addr->mask[15], addr->mask[14],
      57              :                                       addr->mask[13], addr->mask[12])));
      58            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      59            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
      60              :                                     _bf_make32(addr->mask[11], addr->mask[10],
      61              :                                                addr->mask[9], addr->mask[8])));
      62            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      63            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
      64              :     }
      65              : 
      66            0 :     if (matcher->op == BF_MATCHER_EQ) {
      67              :         /* If we want to match an IP, both addr->addr[0] and addr->addr[1]
      68              :          * must match the packet, otherwise we jump to the next rule. */
      69            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
      70              :                                     _bf_make32(addr->addr[7] & addr->mask[7],
      71              :                                                addr->addr[6] & addr->mask[6],
      72              :                                                addr->addr[5] & addr->mask[5],
      73              :                                                addr->addr[4] & addr->mask[4])));
      74            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      75            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
      76              :                                     _bf_make32(addr->addr[3] & addr->mask[3],
      77              :                                                addr->addr[2] & addr->mask[2],
      78              :                                                addr->addr[1] & addr->mask[1],
      79              :                                                addr->addr[0] & addr->mask[0])));
      80            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      81            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      82              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
      83              : 
      84            0 :         EMIT(program,
      85              :              BPF_MOV32_IMM(BPF_REG_3,
      86              :                            _bf_make32(addr->addr[15] & addr->mask[15],
      87              :                                       addr->addr[14] & addr->mask[14],
      88              :                                       addr->addr[13] & addr->mask[13],
      89              :                                       addr->addr[12] & addr->mask[12])));
      90            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      91            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
      92              :                                     _bf_make32(addr->addr[11] & addr->mask[11],
      93              :                                                addr->addr[10] & addr->mask[10],
      94              :                                                addr->addr[9] & addr->mask[9],
      95              :                                                addr->addr[8] & addr->mask[8])));
      96            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      97            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      98              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
      99              :     } else {
     100              :         /* If we want to *not* match an IP, none of addr->addr[0] and
     101              :          * addr->addr[1] should match the packet, otherwise we jump to the
     102              :          * next rule. */
     103            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
     104              :                                     _bf_make32(addr->addr[7] & addr->mask[7],
     105              :                                                addr->addr[6] & addr->mask[6],
     106              :                                                addr->addr[5] & addr->mask[5],
     107              :                                                addr->addr[4] & addr->mask[4])));
     108            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     109            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     110              :                                     _bf_make32(addr->addr[3] & addr->mask[3],
     111              :                                                addr->addr[2] & addr->mask[2],
     112              :                                                addr->addr[1] & addr->mask[1],
     113              :                                                addr->addr[0] & addr->mask[0])));
     114            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     115              : 
     116              :         /* Branching:
     117              :          * - addr->addr[0] matches the address' 64 MSB: continue to compare
     118              :          *   the address' 64 LSB.
     119              :          * - addr->addr[0] doesn't matches the address' 64 MSB: jump to the
     120              :          *   end of the matcher to continue the processing of the current rule.
     121              :          *   This matcher matched. */
     122            0 :         j0 = bf_jmpctx_get(program,
     123              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     124              : 
     125            0 :         EMIT(program,
     126              :              BPF_MOV32_IMM(BPF_REG_3,
     127              :                            _bf_make32(addr->addr[15] & addr->mask[15],
     128              :                                       addr->addr[14] & addr->mask[14],
     129              :                                       addr->addr[13] & addr->mask[13],
     130              :                                       addr->addr[12] & addr->mask[12])));
     131            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     132            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     133              :                                     _bf_make32(addr->addr[11] & addr->mask[11],
     134              :                                                addr->addr[10] & addr->mask[10],
     135              :                                                addr->addr[9] & addr->mask[9],
     136              :                                                addr->addr[8] & addr->mask[8])));
     137            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     138              : 
     139              :         /* Branching:
     140              :          * - addr->addr[1] matches the address' 64 LSB: addr->addr matches the
     141              :          *   packet's address, meaning the matcher doesn't match. Jump to the
     142              :          *   next rule.
     143              :          * - addr->addr[1] doesn't matches the address' 64 LSB: the matcher
     144              :          *   matched: addr->addr is not equal to the packet's address. Continue
     145              :          *   processing with the next matcher. */
     146            0 :         j1 = bf_jmpctx_get(program,
     147              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     148              : 
     149            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     150              : 
     151              :         // j0 and j1 should jump here if they can't match the packet's IP.
     152            0 :         bf_jmpctx_cleanup(&j0);
     153            0 :         bf_jmpctx_cleanup(&j1);
     154              :     }
     155              : 
     156              :     return 0;
     157              : }
     158              : 
     159            0 : static int _bf_matcher_generate_ip6_net(struct bf_program *program,
     160              :                                         const struct bf_matcher *matcher)
     161              : {
     162              :     uint32_t set_id;
     163              :     struct bf_set *set;
     164              :     int16_t offset;
     165              : 
     166            0 :     bf_assert(program && matcher);
     167              : 
     168            0 :     set_id = *(uint32_t *)matcher->payload;
     169            0 :     set = bf_list_get_at(&program->runtime.chain->sets, set_id);
     170            0 :     if (!set)
     171            0 :         return bf_err_r(-ENOENT, "set #%d not found", set_id);
     172              : 
     173            0 :     switch (set->type) {
     174            0 :     case BF_SET_IP6_SUBNET:
     175              :         // Copy bf_ip6_lpm_key entries starting at scratch offset 4, so the
     176              :         // 64-bits copies for the address will be aligned
     177            0 :         offset = matcher->type == BF_MATCHER_IP6_SNET ?
     178              :                     offsetof(struct ipv6hdr, saddr) :
     179              :                     offsetof(struct ipv6hdr, daddr);
     180            0 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 128));
     181            0 :         EMIT(program,
     182              :              BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_3, BF_PROG_SCR_OFF(4)));
     183              : 
     184            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset));
     185            0 :         EMIT(program,
     186              :             BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(8)));
     187            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
     188            0 :         EMIT(program,
     189              :             BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(16)));
     190              :         break;
     191            0 :     default:
     192            0 :         return bf_err_r(-EINVAL, "unsupported set type: %s",
     193              :                         bf_set_type_to_str(set->type));
     194              :     }
     195              : 
     196            0 :     EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
     197            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
     198            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(4)));
     199              : 
     200            0 :     EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
     201              : 
     202              :     // Jump to the next rule if map_lookup_elem returned 0
     203            0 :     EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
     204              : 
     205            0 :     return 0;
     206              : }
     207              : 
     208            0 : int bf_matcher_generate_ip6(struct bf_program *program,
     209              :                             const struct bf_matcher *matcher)
     210              : {
     211              :     int r;
     212              : 
     213            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
     214              :         program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
     215              : 
     216            0 :     EMIT(program,
     217              :          BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
     218              : 
     219            0 :     switch (matcher->type) {
     220            0 :     case BF_MATCHER_IP6_SADDR:
     221              :     case BF_MATCHER_IP6_DADDR:
     222            0 :         r = _bf_matcher_generate_ip6_addr(program, matcher);
     223            0 :         break;
     224            0 :     case BF_MATCHER_IP6_SNET:
     225              :     case BF_MATCHER_IP6_DNET:
     226            0 :         r = _bf_matcher_generate_ip6_net(program, matcher);
     227            0 :         break;
     228            0 :     default:
     229            0 :         return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
     230              :     };
     231              : 
     232              :     return r;
     233              : }
        

Generated by: LCOV version 2.0-1