LCOV - code coverage report
Current view: top level - bpfilter/cgen/matcher - ip6.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 112 0
Test Date: 2025-09-30 16:37:25 Functions: 0.0 % 5 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/ip6.h"
       7              : 
       8              : #include <linux/bpf.h>
       9              : #include <linux/bpf_common.h>
      10              : #include <linux/if_ether.h>
      11              : #include <linux/in.h>
      12              : #include <linux/ipv6.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/jmp.h"
      23              : #include "cgen/program.h"
      24              : #include "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            0 :     uint8_t *addr = (uint8_t *)bf_matcher_payload(matcher);
      42            0 :     size_t offset = bf_matcher_get_type(matcher) == 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 (bf_matcher_get_op(matcher) == 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 void _bf_ip6_prefix_to_mask(uint32_t prefixlen, uint8_t *mask)
     117              : {
     118            0 :     bf_assert(mask);
     119              : 
     120            0 :     memset(mask, 0x00, 16);
     121              : 
     122            0 :     memset(mask, 0xff, prefixlen / 8);
     123            0 :     if (prefixlen % 8)
     124            0 :         mask[prefixlen / 8] = 0xff << (8 - prefixlen % 8) & 0xff;
     125            0 : }
     126              : 
     127            0 : static int _bf_matcher_generate_ip6_net(struct bf_program *program,
     128              :                                         const struct bf_matcher *matcher)
     129              : {
     130              :     uint8_t mask[16];
     131              :     struct bf_jmpctx j0, j1;
     132            0 :     const struct bf_ip6_lpm_key *addr = bf_matcher_payload(matcher);
     133            0 :     size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_IP6_SNET ?
     134            0 :                         offsetof(struct ipv6hdr, saddr) :
     135              :                         offsetof(struct ipv6hdr, daddr);
     136              : 
     137            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
     138            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
     139              : 
     140            0 :     _bf_ip6_prefix_to_mask(addr->prefixlen, mask);
     141              : 
     142            0 :     if (mask[_BF_MASK_LAST_BYTE] != (uint8_t)~0) {
     143            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(mask[7], mask[6],
     144              :                                                           mask[5], mask[4])));
     145            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     146            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(mask[3], mask[2],
     147              :                                                           mask[1], mask[0])));
     148            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     149            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
     150              : 
     151            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(mask[15], mask[14],
     152              :                                                           mask[13], mask[12])));
     153            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     154            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(mask[11], mask[10],
     155              :                                                           mask[9], mask[8])));
     156            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     157            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
     158              :     }
     159              : 
     160            0 :     if (bf_matcher_get_op(matcher) == BF_MATCHER_EQ) {
     161              :         /* If we want to match an IP, both addr->data[0] and addr->data[1]
     162              :          * must match the packet, otherwise we jump to the next rule. */
     163            0 :         EMIT(program,
     164              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[7] & mask[7],
     165              :                                                  addr->data[6] & mask[6],
     166              :                                                  addr->data[5] & mask[5],
     167              :                                                  addr->data[4] & mask[4])));
     168            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     169            0 :         EMIT(program,
     170              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[3] & mask[3],
     171              :                                                  addr->data[2] & mask[2],
     172              :                                                  addr->data[1] & mask[1],
     173              :                                                  addr->data[0] & mask[0])));
     174            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     175            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     176              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     177              : 
     178            0 :         EMIT(program,
     179              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[15] & mask[15],
     180              :                                                  addr->data[14] & mask[14],
     181              :                                                  addr->data[13] & mask[13],
     182              :                                                  addr->data[12] & mask[12])));
     183            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     184            0 :         EMIT(program,
     185              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[11] & mask[11],
     186              :                                                  addr->data[10] & mask[10],
     187              :                                                  addr->data[9] & mask[9],
     188              :                                                  addr->data[8] & mask[8])));
     189            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     190            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     191              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     192              :     } else {
     193              :         /* If we want to *not* match an IP, none of addr->data[0] and
     194              :          * addr->data[1] should match the packet, otherwise we jump to the
     195              :          * next rule. */
     196            0 :         EMIT(program,
     197              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[7] & mask[7],
     198              :                                                  addr->data[6] & mask[6],
     199              :                                                  addr->data[5] & mask[5],
     200              :                                                  addr->data[4] & mask[4])));
     201            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     202            0 :         EMIT(program,
     203              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[3] & mask[3],
     204              :                                                  addr->data[2] & mask[2],
     205              :                                                  addr->data[1] & mask[1],
     206              :                                                  addr->data[0] & mask[0])));
     207            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     208              : 
     209              :         /* Branching:
     210              :          * - addr->data[0] matches the address' 64 MSB: continue to compare
     211              :          *   the address' 64 LSB.
     212              :          * - addr->data[0] doesn't matches the address' 64 MSB: jump to the
     213              :          *   end of the matcher to continue the processing of the current rule.
     214              :          *   This matcher matched. */
     215            0 :         j0 = bf_jmpctx_get(program,
     216              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     217              : 
     218            0 :         EMIT(program,
     219              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[15] & mask[15],
     220              :                                                  addr->data[14] & mask[14],
     221              :                                                  addr->data[13] & mask[13],
     222              :                                                  addr->data[12] & mask[12])));
     223            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     224            0 :         EMIT(program,
     225              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[11] & mask[11],
     226              :                                                  addr->data[10] & mask[10],
     227              :                                                  addr->data[9] & mask[9],
     228              :                                                  addr->data[8] & mask[8])));
     229            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     230              : 
     231              :         /* Branching:
     232              :          * - addr->data[1] matches the address' 64 LSB: addr->data matches the
     233              :          *   packet's address, meaning the matcher doesn't match. Jump to the
     234              :          *   next rule.
     235              :          * - addr->data[1] doesn't matches the address' 64 LSB: the matcher
     236              :          *   matched: addr->data is not equal to the packet's address. Continue
     237              :          *   processing with the next matcher. */
     238            0 :         j1 = bf_jmpctx_get(program,
     239              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     240              : 
     241            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     242              : 
     243              :         // j0 and j1 should jump here if they can't match the packet's IP.
     244            0 :         bf_jmpctx_cleanup(&j0);
     245            0 :         bf_jmpctx_cleanup(&j1);
     246              :     }
     247              : 
     248              :     return 0;
     249              : }
     250              : 
     251            0 : static int _bf_matcher_generate_ip6_nexthdr(struct bf_program *program,
     252              :                                             const struct bf_matcher *matcher)
     253              : {
     254            0 :     const uint8_t ehdr = *(uint8_t *)bf_matcher_payload(matcher);
     255              :     uint8_t eh_mask;
     256              : 
     257            0 :     if ((bf_matcher_get_op(matcher) != BF_MATCHER_EQ) &&
     258            0 :         (bf_matcher_get_op(matcher) != BF_MATCHER_NE))
     259              :         return -EINVAL;
     260              : 
     261            0 :     switch (ehdr) {
     262            0 :     case IPPROTO_HOPOPTS:
     263              :     case IPPROTO_ROUTING:
     264              :     case IPPROTO_DSTOPTS:
     265              :     case IPPROTO_FRAGMENT:
     266              :     case IPPROTO_AH:
     267              :     case IPPROTO_MH:
     268            0 :         eh_mask = (BF_IPV6_EH_HOPOPTS(ehdr == IPPROTO_HOPOPTS) |
     269            0 :                    BF_IPV6_EH_ROUTING(ehdr == IPPROTO_ROUTING) |
     270            0 :                    BF_IPV6_EH_FRAGMENT(ehdr == IPPROTO_FRAGMENT) |
     271            0 :                    BF_IPV6_EH_AH(ehdr == IPPROTO_AH) |
     272            0 :                    BF_IPV6_EH_DSTOPTS(ehdr == IPPROTO_DSTOPTS) |
     273              :                    BF_IPV6_EH_MH(ehdr == IPPROTO_MH));
     274            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10,
     275              :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     276            0 :         EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, eh_mask));
     277            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     278              :             program, BPF_JMP_IMM((bf_matcher_get_op(matcher) == BF_MATCHER_EQ) ?
     279              :                                      BPF_JEQ :
     280              :                                      BPF_JNE,
     281              :                                  BPF_REG_1, 0, 0));
     282            0 :         break;
     283            0 :     default:
     284              :         /* check l4 protocols using BPF_REG_8 */
     285            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     286              :             program, BPF_JMP_IMM((bf_matcher_get_op(matcher) == BF_MATCHER_EQ) ?
     287              :                                      BPF_JNE :
     288              :                                      BPF_JEQ,
     289              :                                  BPF_REG_8, ehdr, 0));
     290            0 :         break;
     291              :     }
     292              : 
     293              :     return 0;
     294              : }
     295              : 
     296            0 : int bf_matcher_generate_ip6(struct bf_program *program,
     297              :                             const struct bf_matcher *matcher)
     298              : {
     299              :     int r;
     300              : 
     301            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
     302              :         program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
     303              : 
     304            0 :     EMIT(program,
     305              :          BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
     306              : 
     307            0 :     switch (bf_matcher_get_type(matcher)) {
     308            0 :     case BF_MATCHER_IP6_SADDR:
     309              :     case BF_MATCHER_IP6_DADDR:
     310            0 :         r = _bf_matcher_generate_ip6_addr(program, matcher);
     311            0 :         break;
     312            0 :     case BF_MATCHER_IP6_SNET:
     313              :     case BF_MATCHER_IP6_DNET:
     314            0 :         r = _bf_matcher_generate_ip6_net(program, matcher);
     315            0 :         break;
     316            0 :     case BF_MATCHER_IP6_NEXTHDR:
     317            0 :         r = _bf_matcher_generate_ip6_nexthdr(program, matcher);
     318            0 :         break;
     319            0 :     default:
     320            0 :         return bf_err_r(-EINVAL, "unknown matcher type %d",
     321              :                         bf_matcher_get_type(matcher));
     322              :     };
     323              : 
     324              :     return r;
     325              : }
        

Generated by: LCOV version 2.0-1