LCOV - code coverage report
Current view: top level - bpfilter/cgen/matcher - ip6.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 131 0
Test Date: 2025-07-24 21:09:26 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 "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              : #define BF_IPV6_EH_HOPOPTS(x) ((x) << 0)
      31              : #define BF_IPV6_EH_ROUTING(x) ((x) << 1)
      32              : #define BF_IPV6_EH_FRAGMENT(x) ((x) << 2)
      33              : #define BF_IPV6_EH_AH(x) ((x) << 3)
      34              : #define BF_IPV6_EH_DSTOPTS(x) ((x) << 4)
      35              : #define BF_IPV6_EH_MH(x) ((x) << 5)
      36              : 
      37            0 : static int _bf_matcher_generate_ip6_addr(struct bf_program *program,
      38              :                                          const struct bf_matcher *matcher)
      39              : {
      40              :     struct bf_jmpctx j0, j1;
      41              :     uint8_t *addr = (uint8_t *)&matcher->payload;
      42            0 :     size_t offset = matcher->type == BF_MATCHER_IP6_SADDR ?
      43            0 :                         offsetof(struct ipv6hdr, saddr) :
      44              :                         offsetof(struct ipv6hdr, daddr);
      45              : 
      46            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
      47            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
      48              : 
      49            0 :     if (matcher->op == BF_MATCHER_EQ) {
      50              :         /* If we want to match an IP, both addr[0] and addr[1]
      51              :          * must match the packet, otherwise we jump to the next rule. */
      52            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[7], addr[6],
      53              :                                                           addr[5], addr[4])));
      54            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      55            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[3], addr[2],
      56              :                                                           addr[1], addr[0])));
      57            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      58            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      59              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
      60              : 
      61            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[15], addr[14],
      62              :                                                           addr[13], addr[12])));
      63            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      64            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[11], addr[10],
      65              :                                                           addr[9], addr[8])));
      66            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      67            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      68              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
      69              :     } else {
      70              :         /* If we want to *not* match an IP, none of addr[0] and
      71              :          * addr[1] should match the packet, otherwise we jump to the
      72              :          * next rule. */
      73            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[7], addr[6],
      74              :                                                           addr[5], addr[4])));
      75            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      76            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[3], addr[2],
      77              :                                                           addr[1], addr[0])));
      78            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      79              : 
      80              :         /* Branching:
      81              :          * - addr[0] matches the address' 64 MSB: continue to compare
      82              :          *   the address' 64 LSB.
      83              :          * - addr[0] doesn't matches the address' 64 MSB: jump to the
      84              :          *   end of the matcher to continue the processing of the current rule.
      85              :          *   This matcher matched. */
      86            0 :         j0 = bf_jmpctx_get(program,
      87              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
      88              : 
      89            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[15], addr[14],
      90              :                                                           addr[13], addr[12])));
      91            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      92            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[11], addr[10],
      93              :                                                           addr[9], addr[8])));
      94            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      95              : 
      96              :         /* Branching:
      97              :          * - addr[1] matches the address' 64 LSB: addr matches the
      98              :          *   packet's address, meaning the matcher doesn't match. Jump to the
      99              :          *   next rule.
     100              :          * - addr[1] doesn't matches the address' 64 LSB: the matcher
     101              :          *   matched: addr is not equal to the packet's address. Continue
     102              :          *   processing with the next matcher. */
     103            0 :         j1 = bf_jmpctx_get(program,
     104              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     105              : 
     106            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     107              : 
     108              :         // j0 and j1 should jump here if they can't match the packet's IP.
     109            0 :         bf_jmpctx_cleanup(&j0);
     110            0 :         bf_jmpctx_cleanup(&j1);
     111              :     }
     112              : 
     113              :     return 0;
     114              : }
     115              : 
     116            0 : static int _bf_matcher_generate_ip6_net_single(struct bf_program *program,
     117              :                                                const struct bf_matcher *matcher)
     118              : {
     119              :     struct bf_jmpctx j0, j1;
     120              :     struct bf_matcher_ip6_addr *addr = (void *)&matcher->payload;
     121            0 :     size_t offset = matcher->type == BF_MATCHER_IP6_SNET ?
     122            0 :                         offsetof(struct ipv6hdr, saddr) :
     123              :                         offsetof(struct ipv6hdr, daddr);
     124              : 
     125            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
     126            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
     127              : 
     128            0 :     if (addr->mask[_BF_MASK_LAST_BYTE] != (uint8_t)~0) {
     129            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
     130              :                                     _bf_make32(addr->mask[7], addr->mask[6],
     131              :                                                addr->mask[5], addr->mask[4])));
     132            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     133            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     134              :                                     _bf_make32(addr->mask[3], addr->mask[2],
     135              :                                                addr->mask[1], addr->mask[0])));
     136            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     137            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
     138              : 
     139            0 :         EMIT(program,
     140              :              BPF_MOV32_IMM(BPF_REG_3,
     141              :                            _bf_make32(addr->mask[15], addr->mask[14],
     142              :                                       addr->mask[13], addr->mask[12])));
     143            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     144            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     145              :                                     _bf_make32(addr->mask[11], addr->mask[10],
     146              :                                                addr->mask[9], addr->mask[8])));
     147            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     148            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
     149              :     }
     150              : 
     151            0 :     if (matcher->op == BF_MATCHER_EQ) {
     152              :         /* If we want to match an IP, both addr->addr[0] and addr->addr[1]
     153              :          * must match the packet, otherwise we jump to the next rule. */
     154            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
     155              :                                     _bf_make32(addr->addr[7] & addr->mask[7],
     156              :                                                addr->addr[6] & addr->mask[6],
     157              :                                                addr->addr[5] & addr->mask[5],
     158              :                                                addr->addr[4] & addr->mask[4])));
     159            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     160            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     161              :                                     _bf_make32(addr->addr[3] & addr->mask[3],
     162              :                                                addr->addr[2] & addr->mask[2],
     163              :                                                addr->addr[1] & addr->mask[1],
     164              :                                                addr->addr[0] & addr->mask[0])));
     165            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     166            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     167              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     168              : 
     169            0 :         EMIT(program,
     170              :              BPF_MOV32_IMM(BPF_REG_3,
     171              :                            _bf_make32(addr->addr[15] & addr->mask[15],
     172              :                                       addr->addr[14] & addr->mask[14],
     173              :                                       addr->addr[13] & addr->mask[13],
     174              :                                       addr->addr[12] & addr->mask[12])));
     175            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     176            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     177              :                                     _bf_make32(addr->addr[11] & addr->mask[11],
     178              :                                                addr->addr[10] & addr->mask[10],
     179              :                                                addr->addr[9] & addr->mask[9],
     180              :                                                addr->addr[8] & addr->mask[8])));
     181            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     182            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     183              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     184              :     } else {
     185              :         /* If we want to *not* match an IP, none of addr->addr[0] and
     186              :          * addr->addr[1] should match the packet, otherwise we jump to the
     187              :          * next rule. */
     188            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
     189              :                                     _bf_make32(addr->addr[7] & addr->mask[7],
     190              :                                                addr->addr[6] & addr->mask[6],
     191              :                                                addr->addr[5] & addr->mask[5],
     192              :                                                addr->addr[4] & addr->mask[4])));
     193            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     194            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     195              :                                     _bf_make32(addr->addr[3] & addr->mask[3],
     196              :                                                addr->addr[2] & addr->mask[2],
     197              :                                                addr->addr[1] & addr->mask[1],
     198              :                                                addr->addr[0] & addr->mask[0])));
     199            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     200              : 
     201              :         /* Branching:
     202              :          * - addr->addr[0] matches the address' 64 MSB: continue to compare
     203              :          *   the address' 64 LSB.
     204              :          * - addr->addr[0] doesn't matches the address' 64 MSB: jump to the
     205              :          *   end of the matcher to continue the processing of the current rule.
     206              :          *   This matcher matched. */
     207            0 :         j0 = bf_jmpctx_get(program,
     208              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     209              : 
     210            0 :         EMIT(program,
     211              :              BPF_MOV32_IMM(BPF_REG_3,
     212              :                            _bf_make32(addr->addr[15] & addr->mask[15],
     213              :                                       addr->addr[14] & addr->mask[14],
     214              :                                       addr->addr[13] & addr->mask[13],
     215              :                                       addr->addr[12] & addr->mask[12])));
     216            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     217            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
     218              :                                     _bf_make32(addr->addr[11] & addr->mask[11],
     219              :                                                addr->addr[10] & addr->mask[10],
     220              :                                                addr->addr[9] & addr->mask[9],
     221              :                                                addr->addr[8] & addr->mask[8])));
     222            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     223              : 
     224              :         /* Branching:
     225              :          * - addr->addr[1] matches the address' 64 LSB: addr->addr matches the
     226              :          *   packet's address, meaning the matcher doesn't match. Jump to the
     227              :          *   next rule.
     228              :          * - addr->addr[1] doesn't matches the address' 64 LSB: the matcher
     229              :          *   matched: addr->addr is not equal to the packet's address. Continue
     230              :          *   processing with the next matcher. */
     231            0 :         j1 = bf_jmpctx_get(program,
     232              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     233              : 
     234            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     235              : 
     236              :         // j0 and j1 should jump here if they can't match the packet's IP.
     237            0 :         bf_jmpctx_cleanup(&j0);
     238            0 :         bf_jmpctx_cleanup(&j1);
     239              :     }
     240              : 
     241              :     return 0;
     242              : }
     243              : 
     244            0 : static int _bf_matcher_generate_ip6_net_in(struct bf_program *program,
     245              :                                            const struct bf_matcher *matcher)
     246              : {
     247              :     uint32_t set_id;
     248              :     struct bf_set *set;
     249            0 :     int16_t offset = matcher->type == BF_MATCHER_IP6_SNET ?
     250              :                          offsetof(struct ipv6hdr, saddr) :
     251              :                          offsetof(struct ipv6hdr, daddr);
     252              : 
     253            0 :     bf_assert(program && matcher);
     254              : 
     255            0 :     set_id = *(uint32_t *)matcher->payload;
     256            0 :     set = bf_list_get_at(&program->runtime.chain->sets, set_id);
     257            0 :     if (!set)
     258            0 :         return bf_err_r(-ENOENT, "set #%d not found", set_id);
     259              : 
     260              :     // Copy bf_ip6_lpm_key entries starting at scratch offset 4, so the
     261              :     // 64-bits copies for the address will be aligned
     262            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 128));
     263            0 :     EMIT(program,
     264              :          BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_3, BF_PROG_SCR_OFF(4)));
     265              : 
     266            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset));
     267            0 :     EMIT(program,
     268              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(8)));
     269            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
     270            0 :     EMIT(program,
     271              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, BF_PROG_SCR_OFF(16)));
     272              : 
     273            0 :     EMIT_LOAD_SET_FD_FIXUP(program, BPF_REG_1, set_id);
     274            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
     275            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(4)));
     276              : 
     277            0 :     EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
     278              : 
     279              :     // Jump to the next rule if map_lookup_elem returned 0
     280            0 :     EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
     281              : 
     282            0 :     return 0;
     283              : }
     284              : 
     285            0 : static int _bf_matcher_generate_ip6_nexthdr(struct bf_program *program,
     286              :                                             const struct bf_matcher *matcher)
     287              : {
     288            0 :     const uint8_t ehdr = matcher->payload[0];
     289              :     uint8_t eh_mask;
     290              : 
     291            0 :     if ((matcher->op != BF_MATCHER_EQ) && (matcher->op != BF_MATCHER_NE))
     292              :         return -EINVAL;
     293              : 
     294            0 :     switch (ehdr) {
     295            0 :     case IPPROTO_HOPOPTS:
     296              :     case IPPROTO_ROUTING:
     297              :     case IPPROTO_DSTOPTS:
     298              :     case IPPROTO_FRAGMENT:
     299              :     case IPPROTO_AH:
     300              :     case IPPROTO_MH:
     301            0 :         eh_mask = (BF_IPV6_EH_HOPOPTS(ehdr == IPPROTO_HOPOPTS) |
     302            0 :                    BF_IPV6_EH_ROUTING(ehdr == IPPROTO_ROUTING) |
     303            0 :                    BF_IPV6_EH_FRAGMENT(ehdr == IPPROTO_FRAGMENT) |
     304            0 :                    BF_IPV6_EH_AH(ehdr == IPPROTO_AH) |
     305            0 :                    BF_IPV6_EH_DSTOPTS(ehdr == IPPROTO_DSTOPTS) |
     306              :                    BF_IPV6_EH_MH(ehdr == IPPROTO_MH));
     307            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10,
     308              :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     309            0 :         EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, eh_mask));
     310            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     311              :             program,
     312              :             BPF_JMP_IMM((matcher->op == BF_MATCHER_EQ) ? BPF_JEQ : BPF_JNE,
     313              :                         BPF_REG_1, 0, 0));
     314            0 :         break;
     315            0 :     default:
     316              :         /* check l4 protocols using BPF_REG_8 */
     317            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     318              :             program,
     319              :             BPF_JMP_IMM((matcher->op == BF_MATCHER_EQ) ? BPF_JNE : BPF_JEQ,
     320              :                         BPF_REG_8, ehdr, 0));
     321            0 :         break;
     322              :     }
     323              : 
     324              :     return 0;
     325              : }
     326              : 
     327            0 : static int _bf_matcher_generate_ip6_net(struct bf_program *program,
     328              :                                         const struct bf_matcher *matcher)
     329              : {
     330            0 :     bf_assert(program && matcher);
     331              : 
     332              :     int r;
     333              : 
     334            0 :     switch (matcher->op) {
     335            0 :     case BF_MATCHER_EQ:
     336              :     case BF_MATCHER_NE:
     337            0 :         r = _bf_matcher_generate_ip6_net_single(program, matcher);
     338            0 :         break;
     339            0 :     case BF_MATCHER_IN:
     340            0 :         r = _bf_matcher_generate_ip6_net_in(program, matcher);
     341            0 :         break;
     342            0 :     default:
     343            0 :         return bf_err_r(-ENOTSUP, "unsupported operator %s for matcher %s",
     344              :                         bf_matcher_type_to_str(matcher->type),
     345              :                         bf_matcher_op_to_str(matcher->op));
     346              :     }
     347              : 
     348              :     return r;
     349              : }
     350              : 
     351            0 : int bf_matcher_generate_ip6(struct bf_program *program,
     352              :                             const struct bf_matcher *matcher)
     353              : {
     354              :     int r;
     355              : 
     356            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
     357              :         program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
     358              : 
     359            0 :     EMIT(program,
     360              :          BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
     361              : 
     362            0 :     switch (matcher->type) {
     363            0 :     case BF_MATCHER_IP6_SADDR:
     364              :     case BF_MATCHER_IP6_DADDR:
     365            0 :         r = _bf_matcher_generate_ip6_addr(program, matcher);
     366            0 :         break;
     367            0 :     case BF_MATCHER_IP6_SNET:
     368              :     case BF_MATCHER_IP6_DNET:
     369            0 :         r = _bf_matcher_generate_ip6_net(program, matcher);
     370            0 :         break;
     371            0 :     case BF_MATCHER_IP6_NEXTHDR:
     372            0 :         r = _bf_matcher_generate_ip6_nexthdr(program, matcher);
     373            0 :         break;
     374            0 :     default:
     375            0 :         return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
     376              :     };
     377              : 
     378              :     return r;
     379              : }
        

Generated by: LCOV version 2.0-1