LCOV - code coverage report
Current view: top level - bpfilter/cgen/matcher - ip6.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 109 0
Test Date: 2025-08-19 17:27:08 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 "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              : 
      23              : #include "external/filter.h"
      24              : 
      25              : #define _bf_make32(a, b, c, d)                                                 \
      26              :     (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) |    \
      27              :      (uint32_t)(d))
      28              : #define _BF_MASK_LAST_BYTE 15
      29              : #define BF_IPV6_EH_HOPOPTS(x) ((x) << 0)
      30              : #define BF_IPV6_EH_ROUTING(x) ((x) << 1)
      31              : #define BF_IPV6_EH_FRAGMENT(x) ((x) << 2)
      32              : #define BF_IPV6_EH_AH(x) ((x) << 3)
      33              : #define BF_IPV6_EH_DSTOPTS(x) ((x) << 4)
      34              : #define BF_IPV6_EH_MH(x) ((x) << 5)
      35              : 
      36            0 : static int _bf_matcher_generate_ip6_addr(struct bf_program *program,
      37              :                                          const struct bf_matcher *matcher)
      38              : {
      39              :     struct bf_jmpctx j0, j1;
      40              :     uint8_t *addr = (uint8_t *)&matcher->payload;
      41            0 :     size_t offset = matcher->type == BF_MATCHER_IP6_SADDR ?
      42            0 :                         offsetof(struct ipv6hdr, saddr) :
      43              :                         offsetof(struct ipv6hdr, daddr);
      44              : 
      45            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
      46            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
      47              : 
      48            0 :     if (matcher->op == BF_MATCHER_EQ) {
      49              :         /* If we want to match an IP, both addr[0] and addr[1]
      50              :          * must match the packet, otherwise we jump to the next rule. */
      51            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[7], addr[6],
      52              :                                                           addr[5], addr[4])));
      53            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      54            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[3], addr[2],
      55              :                                                           addr[1], addr[0])));
      56            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      57            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      58              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
      59              : 
      60            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[15], addr[14],
      61              :                                                           addr[13], addr[12])));
      62            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      63            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[11], addr[10],
      64              :                                                           addr[9], addr[8])));
      65            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      66            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
      67              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
      68              :     } else {
      69              :         /* If we want to *not* match an IP, none of addr[0] and
      70              :          * addr[1] should match the packet, otherwise we jump to the
      71              :          * next rule. */
      72            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[7], addr[6],
      73              :                                                           addr[5], addr[4])));
      74            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      75            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[3], addr[2],
      76              :                                                           addr[1], addr[0])));
      77            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      78              : 
      79              :         /* Branching:
      80              :          * - addr[0] matches the address' 64 MSB: continue to compare
      81              :          *   the address' 64 LSB.
      82              :          * - addr[0] doesn't matches the address' 64 MSB: jump to the
      83              :          *   end of the matcher to continue the processing of the current rule.
      84              :          *   This matcher matched. */
      85            0 :         j0 = bf_jmpctx_get(program,
      86              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
      87              : 
      88            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr[15], addr[14],
      89              :                                                           addr[13], addr[12])));
      90            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
      91            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr[11], addr[10],
      92              :                                                           addr[9], addr[8])));
      93            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
      94              : 
      95              :         /* Branching:
      96              :          * - addr[1] matches the address' 64 LSB: addr matches the
      97              :          *   packet's address, meaning the matcher doesn't match. Jump to the
      98              :          *   next rule.
      99              :          * - addr[1] doesn't matches the address' 64 LSB: the matcher
     100              :          *   matched: addr is not equal to the packet's address. Continue
     101              :          *   processing with the next matcher. */
     102            0 :         j1 = bf_jmpctx_get(program,
     103              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     104              : 
     105            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     106              : 
     107              :         // j0 and j1 should jump here if they can't match the packet's IP.
     108            0 :         bf_jmpctx_cleanup(&j0);
     109            0 :         bf_jmpctx_cleanup(&j1);
     110              :     }
     111              : 
     112              :     return 0;
     113              : }
     114              : 
     115            0 : static void _bf_ip6_prefix_to_mask(uint32_t prefixlen, uint8_t *mask)
     116              : {
     117            0 :     bf_assert(mask);
     118              : 
     119            0 :     memset(mask, 0x00, 16);
     120              : 
     121            0 :     memset(mask, 0xff, prefixlen / 8);
     122            0 :     if (prefixlen % 8)
     123            0 :         mask[prefixlen / 8] = 0xff << (8 - prefixlen % 8) & 0xff;
     124            0 : }
     125              : 
     126            0 : static int _bf_matcher_generate_ip6_net(struct bf_program *program,
     127              :                                         const struct bf_matcher *matcher)
     128              : {
     129              :     uint8_t mask[16];
     130              :     struct bf_jmpctx j0, j1;
     131              :     struct bf_ip6_lpm_key *addr = (void *)&matcher->payload;
     132            0 :     size_t offset = matcher->type == BF_MATCHER_IP6_SNET ?
     133            0 :                         offsetof(struct ipv6hdr, saddr) :
     134              :                         offsetof(struct ipv6hdr, daddr);
     135              : 
     136            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
     137            0 :     EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
     138              : 
     139            0 :     _bf_ip6_prefix_to_mask(addr->prefixlen, mask);
     140              : 
     141            0 :     if (mask[_BF_MASK_LAST_BYTE] != (uint8_t)~0) {
     142            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(mask[7], mask[6],
     143              :                                                           mask[5], mask[4])));
     144            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     145            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(mask[3], mask[2],
     146              :                                                           mask[1], mask[0])));
     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_1, BPF_REG_3));
     149              : 
     150            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, _bf_make32(mask[15], mask[14],
     151              :                                                           mask[13], mask[12])));
     152            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     153            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_4, _bf_make32(mask[11], mask[10],
     154              :                                                           mask[9], mask[8])));
     155            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     156            0 :         EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
     157              :     }
     158              : 
     159            0 :     if (matcher->op == BF_MATCHER_EQ) {
     160              :         /* If we want to match an IP, both addr->data[0] and addr->data[1]
     161              :          * must match the packet, otherwise we jump to the next rule. */
     162            0 :         EMIT(program,
     163              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[7] & mask[7],
     164              :                                                  addr->data[6] & mask[6],
     165              :                                                  addr->data[5] & mask[5],
     166              :                                                  addr->data[4] & mask[4])));
     167            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     168            0 :         EMIT(program,
     169              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[3] & mask[3],
     170              :                                                  addr->data[2] & mask[2],
     171              :                                                  addr->data[1] & mask[1],
     172              :                                                  addr->data[0] & mask[0])));
     173            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     174            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     175              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     176              : 
     177            0 :         EMIT(program,
     178              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[15] & mask[15],
     179              :                                                  addr->data[14] & mask[14],
     180              :                                                  addr->data[13] & mask[13],
     181              :                                                  addr->data[12] & mask[12])));
     182            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     183            0 :         EMIT(program,
     184              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[11] & mask[11],
     185              :                                                  addr->data[10] & mask[10],
     186              :                                                  addr->data[9] & mask[9],
     187              :                                                  addr->data[8] & mask[8])));
     188            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     189            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program,
     190              :                                  BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     191              :     } else {
     192              :         /* If we want to *not* match an IP, none of addr->data[0] and
     193              :          * addr->data[1] should match the packet, otherwise we jump to the
     194              :          * next rule. */
     195            0 :         EMIT(program,
     196              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[7] & mask[7],
     197              :                                                  addr->data[6] & mask[6],
     198              :                                                  addr->data[5] & mask[5],
     199              :                                                  addr->data[4] & mask[4])));
     200            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     201            0 :         EMIT(program,
     202              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[3] & mask[3],
     203              :                                                  addr->data[2] & mask[2],
     204              :                                                  addr->data[1] & mask[1],
     205              :                                                  addr->data[0] & mask[0])));
     206            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     207              : 
     208              :         /* Branching:
     209              :          * - addr->data[0] matches the address' 64 MSB: continue to compare
     210              :          *   the address' 64 LSB.
     211              :          * - addr->data[0] doesn't matches the address' 64 MSB: jump to the
     212              :          *   end of the matcher to continue the processing of the current rule.
     213              :          *   This matcher matched. */
     214            0 :         j0 = bf_jmpctx_get(program,
     215              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
     216              : 
     217            0 :         EMIT(program,
     218              :              BPF_MOV32_IMM(BPF_REG_3, _bf_make32(addr->data[15] & mask[15],
     219              :                                                  addr->data[14] & mask[14],
     220              :                                                  addr->data[13] & mask[13],
     221              :                                                  addr->data[12] & mask[12])));
     222            0 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
     223            0 :         EMIT(program,
     224              :              BPF_MOV32_IMM(BPF_REG_4, _bf_make32(addr->data[11] & mask[11],
     225              :                                                  addr->data[10] & mask[10],
     226              :                                                  addr->data[9] & mask[9],
     227              :                                                  addr->data[8] & mask[8])));
     228            0 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
     229              : 
     230              :         /* Branching:
     231              :          * - addr->data[1] matches the address' 64 LSB: addr->data matches the
     232              :          *   packet's address, meaning the matcher doesn't match. Jump to the
     233              :          *   next rule.
     234              :          * - addr->data[1] doesn't matches the address' 64 LSB: the matcher
     235              :          *   matched: addr->data is not equal to the packet's address. Continue
     236              :          *   processing with the next matcher. */
     237            0 :         j1 = bf_jmpctx_get(program,
     238              :                            BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
     239              : 
     240            0 :         EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
     241              : 
     242              :         // j0 and j1 should jump here if they can't match the packet's IP.
     243            0 :         bf_jmpctx_cleanup(&j0);
     244            0 :         bf_jmpctx_cleanup(&j1);
     245              :     }
     246              : 
     247              :     return 0;
     248              : }
     249              : 
     250            0 : static int _bf_matcher_generate_ip6_nexthdr(struct bf_program *program,
     251              :                                             const struct bf_matcher *matcher)
     252              : {
     253            0 :     const uint8_t ehdr = matcher->payload[0];
     254              :     uint8_t eh_mask;
     255              : 
     256            0 :     if ((matcher->op != BF_MATCHER_EQ) && (matcher->op != BF_MATCHER_NE))
     257              :         return -EINVAL;
     258              : 
     259            0 :     switch (ehdr) {
     260            0 :     case IPPROTO_HOPOPTS:
     261              :     case IPPROTO_ROUTING:
     262              :     case IPPROTO_DSTOPTS:
     263              :     case IPPROTO_FRAGMENT:
     264              :     case IPPROTO_AH:
     265              :     case IPPROTO_MH:
     266            0 :         eh_mask = (BF_IPV6_EH_HOPOPTS(ehdr == IPPROTO_HOPOPTS) |
     267            0 :                    BF_IPV6_EH_ROUTING(ehdr == IPPROTO_ROUTING) |
     268            0 :                    BF_IPV6_EH_FRAGMENT(ehdr == IPPROTO_FRAGMENT) |
     269            0 :                    BF_IPV6_EH_AH(ehdr == IPPROTO_AH) |
     270            0 :                    BF_IPV6_EH_DSTOPTS(ehdr == IPPROTO_DSTOPTS) |
     271              :                    BF_IPV6_EH_MH(ehdr == IPPROTO_MH));
     272            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10,
     273              :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     274            0 :         EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, eh_mask));
     275            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     276              :             program,
     277              :             BPF_JMP_IMM((matcher->op == BF_MATCHER_EQ) ? BPF_JEQ : BPF_JNE,
     278              :                         BPF_REG_1, 0, 0));
     279            0 :         break;
     280            0 :     default:
     281              :         /* check l4 protocols using BPF_REG_8 */
     282            0 :         EMIT_FIXUP_JMP_NEXT_RULE(
     283              :             program,
     284              :             BPF_JMP_IMM((matcher->op == BF_MATCHER_EQ) ? BPF_JNE : BPF_JEQ,
     285              :                         BPF_REG_8, ehdr, 0));
     286            0 :         break;
     287              :     }
     288              : 
     289              :     return 0;
     290              : }
     291              : 
     292            0 : int bf_matcher_generate_ip6(struct bf_program *program,
     293              :                             const struct bf_matcher *matcher)
     294              : {
     295              :     int r;
     296              : 
     297            0 :     EMIT_FIXUP_JMP_NEXT_RULE(
     298              :         program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
     299              : 
     300            0 :     EMIT(program,
     301              :          BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
     302              : 
     303            0 :     switch (matcher->type) {
     304            0 :     case BF_MATCHER_IP6_SADDR:
     305              :     case BF_MATCHER_IP6_DADDR:
     306            0 :         r = _bf_matcher_generate_ip6_addr(program, matcher);
     307            0 :         break;
     308            0 :     case BF_MATCHER_IP6_SNET:
     309              :     case BF_MATCHER_IP6_DNET:
     310            0 :         r = _bf_matcher_generate_ip6_net(program, matcher);
     311            0 :         break;
     312            0 :     case BF_MATCHER_IP6_NEXTHDR:
     313            0 :         r = _bf_matcher_generate_ip6_nexthdr(program, matcher);
     314            0 :         break;
     315            0 :     default:
     316            0 :         return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
     317              :     };
     318              : 
     319              :     return r;
     320              : }
        

Generated by: LCOV version 2.0-1