LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 95.3 % 403 384
Test Date: 2025-11-24 12:34:34 Functions: 96.7 % 61 59
Branches: 81.2 % 293 238

             Branch data     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/matcher.h"
       7                 :             : 
       8                 :             : #include <linux/icmp.h>
       9                 :             : #include <linux/icmpv6.h>
      10                 :             : #include <linux/if_ether.h>
      11                 :             : #include <linux/in.h>
      12                 :             : #include <linux/in6.h>
      13                 :             : #include <linux/ip.h>
      14                 :             : #include <linux/ipv6.h>
      15                 :             : #include <linux/tcp.h>
      16                 :             : #include <linux/udp.h>
      17                 :             : 
      18                 :             : #include <ctype.h>
      19                 :             : #include <endian.h>
      20                 :             : #include <errno.h>
      21                 :             : #include <inttypes.h>
      22                 :             : #include <limits.h>
      23                 :             : #include <stdint.h>
      24                 :             : #include <stdlib.h>
      25                 :             : #include <string.h>
      26                 :             : 
      27                 :             : #include "bpfilter/dump.h"
      28                 :             : #include "bpfilter/helper.h"
      29                 :             : #include "bpfilter/hook.h"
      30                 :             : #include "bpfilter/if.h"
      31                 :             : #include "bpfilter/logger.h"
      32                 :             : #include "bpfilter/pack.h"
      33                 :             : #include "bpfilter/runtime.h"
      34                 :             : 
      35                 :             : #define INET4_ADDRSTRLEN 16
      36                 :             : #define INET6_ADDRSTRLEN 46
      37                 :             : 
      38                 :             : #define BF_PAYLOAD_OPS(type, size, parser_cb, printer_cb)                      \
      39                 :             :     [type] = {size, parser_cb, printer_cb}
      40                 :             : 
      41                 :             : extern int inet_pton(int, const char *, void *);
      42                 :             : extern const char *inet_ntop(int, const void *, char *, socklen_t);
      43                 :             : 
      44                 :             : /**
      45                 :             :  * Matcher definition.
      46                 :             :  *
      47                 :             :  * Matchers are criterias to match the packet against. A set of matcher defines
      48                 :             :  * what a rule should match on.
      49                 :             :  *
      50                 :             :  * @todo `bf_matcher`'s payload should be a union of all the possible payload
      51                 :             :  * types.
      52                 :             :  */
      53                 :             : struct bf_matcher
      54                 :             : {
      55                 :             :     /// Matcher type.
      56                 :             :     enum bf_matcher_type type;
      57                 :             :     /// Comparison operator.
      58                 :             :     enum bf_matcher_op op;
      59                 :             :     /// Total matcher size (including payload).
      60                 :             :     size_t len;
      61                 :             :     /// Payload to match the packet against (if any).
      62                 :             :     uint8_t payload[];
      63                 :             : };
      64                 :             : 
      65                 :          46 : int _bf_parse_int(enum bf_matcher_type type, enum bf_matcher_op op,
      66                 :             :                   void *payload, const char *raw_payload)
      67                 :             : {
      68                 :             :     bf_assert(payload && raw_payload);
      69                 :             : 
      70                 :             :     unsigned long value;
      71                 :             :     char *endptr;
      72                 :             : 
      73                 :          46 :     value = strtoul(raw_payload, &endptr, BF_BASE_10);
      74   [ +  +  +  + ]:          46 :     if (*endptr == '\0' && value <= UINT32_MAX) {
      75                 :          20 :         *(uint32_t *)payload = (uint32_t)value;
      76                 :          20 :         return 0;
      77                 :             :     }
      78                 :             : 
      79                 :          26 :     value = strtoul(raw_payload, &endptr, BF_BASE_16);
      80   [ +  +  +  + ]:          26 :     if (*endptr == '\0' && value <= UINT32_MAX) {
      81                 :          16 :         *(uint32_t *)payload = (uint32_t)value;
      82                 :          16 :         return 0;
      83                 :             :     }
      84                 :             : 
      85         [ +  - ]:          10 :     bf_err(
      86                 :             :         "\"%s %s\" expects a valid 32 bits integer value in decimal or hexadecimal notation, not '%s'",
      87                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
      88                 :             : 
      89                 :             :     return -EINVAL;
      90                 :             : }
      91                 :             : 
      92                 :           0 : void _bf_print_int(const void *payload)
      93                 :             : {
      94                 :             :     bf_assert(payload);
      95                 :             : 
      96                 :           0 :     (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
      97                 :           0 : }
      98                 :             : 
      99                 :             : #define BF_INT_RANGE_MAX_LEN 32 /* 4294967295-4294967295 */
     100                 :             : 
     101                 :          24 : int _bf_parse_int_range(enum bf_matcher_type type, enum bf_matcher_op op,
     102                 :             :                         void *payload, const char *raw_payload)
     103                 :             : {
     104                 :             :     bf_assert(payload && raw_payload);
     105                 :             : 
     106                 :             :     uint32_t *range = (uint32_t *)payload;
     107                 :             :     unsigned long value;
     108                 :             :     char buf[BF_INT_RANGE_MAX_LEN];
     109                 :             :     char *first;
     110                 :             :     char *second;
     111                 :             :     char *endptr;
     112                 :             : 
     113                 :          24 :     bf_strncpy(buf, BF_INT_RANGE_MAX_LEN, raw_payload);
     114                 :             : 
     115         [ -  + ]:          24 :     if (!isdigit(*raw_payload))
     116                 :           0 :         goto err;
     117                 :             : 
     118                 :          24 :     first = strtok_r(buf, "-", &second);
     119         [ -  + ]:          24 :     if (!first)
     120                 :           0 :         goto err;
     121                 :             : 
     122         [ +  + ]:          24 :     if (!*second)
     123                 :           1 :         goto err;
     124                 :             : 
     125                 :          23 :     value = strtoul(first, &endptr, BF_BASE_10);
     126   [ +  +  -  + ]:          23 :     if (*endptr != '\0' || value > UINT32_MAX) {
     127                 :          12 :         value = strtoul(first, &endptr, BF_BASE_16);
     128   [ +  +  -  + ]:          12 :         if (*endptr != '\0' || value > UINT32_MAX)
     129                 :           1 :             goto err;
     130                 :             :     }
     131                 :          22 :     range[0] = (uint32_t)value;
     132                 :             : 
     133                 :          22 :     value = strtoul(second, &endptr, BF_BASE_10);
     134   [ +  +  -  + ]:          22 :     if (*endptr != '\0' || value > UINT32_MAX) {
     135                 :          12 :         value = strtoul(second, &endptr, BF_BASE_16);
     136   [ +  -  -  + ]:          12 :         if (*endptr != '\0' || value > UINT32_MAX)
     137                 :           0 :             goto err;
     138                 :             :     }
     139                 :          22 :     range[1] = (uint32_t)value;
     140                 :             : 
     141         [ +  + ]:          22 :     if (range[1] < range[0])
     142                 :           2 :         goto err;
     143                 :             : 
     144                 :             :     return 0;
     145                 :             : 
     146                 :           4 : err:
     147         [ +  - ]:           4 :     bf_err(
     148                 :             :         "\"%s %s\" expects two positive decimal and hexadecimal integers as `$START-$END`, with `$START <= $END`, not '%s'",
     149                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     150                 :             : 
     151                 :             :     return -EINVAL;
     152                 :             : }
     153                 :             : 
     154                 :           0 : void _bf_print_int_range(const void *payload)
     155                 :             : {
     156                 :             :     bf_assert(payload);
     157                 :             : 
     158                 :             :     uint32_t *range = (uint32_t *)payload;
     159                 :             : 
     160                 :           0 :     (void)fprintf(stdout, "0x%" PRIx32 "-0x%" PRIx32, range[0], range[1]);
     161                 :           0 : }
     162                 :             : 
     163                 :          38 : int _bf_parse_iface(enum bf_matcher_type type, enum bf_matcher_op op,
     164                 :             :                     void *payload, const char *raw_payload)
     165                 :             : {
     166                 :             :     bf_assert(payload && raw_payload);
     167                 :             : 
     168                 :             :     int idx;
     169                 :             :     unsigned long ifindex;
     170                 :             :     char *endptr;
     171                 :             : 
     172                 :          38 :     idx = bf_if_index_from_name(raw_payload);
     173         [ +  + ]:          38 :     if (idx > 0) {
     174                 :          11 :         *(uint32_t *)payload = (uint32_t)idx;
     175                 :          11 :         return 0;
     176                 :             :     }
     177                 :             : 
     178                 :          27 :     ifindex = strtoul(raw_payload, &endptr, BF_BASE_10);
     179   [ +  +  +  + ]:          27 :     if (*endptr == '\0' && 0 < ifindex && ifindex <= UINT32_MAX) {
     180                 :          16 :         *(uint32_t *)payload = (uint32_t)ifindex;
     181                 :          16 :         return 0;
     182                 :             :     }
     183                 :             : 
     184         [ +  - ]:          11 :     bf_err(
     185                 :             :         "\"%s %s\" expects an interface name (e.g., \"eth0\", \"wlan0\") or a decimal interface index (e.g., \"1\", \"2\"), not '%s'",
     186                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     187                 :             : 
     188                 :             :     return -EINVAL;
     189                 :             : }
     190                 :             : 
     191                 :           2 : void _bf_print_iface(const void *payload)
     192                 :             : {
     193                 :             :     bf_assert(payload);
     194                 :             : 
     195                 :             :     const char *ifname;
     196                 :           2 :     uint32_t ifindex = *(uint32_t *)payload;
     197                 :             : 
     198                 :           2 :     ifname = bf_if_name_from_index((int)ifindex);
     199         [ +  + ]:           2 :     if (ifname)
     200                 :           1 :         (void)fprintf(stdout, "%s", ifname);
     201                 :             :     else
     202                 :           1 :         (void)fprintf(stdout, "%" PRIu32, ifindex);
     203                 :           2 : }
     204                 :             : 
     205                 :          79 : int _bf_parse_l3_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     206                 :             :                        void *payload, const char *raw_payload)
     207                 :             : {
     208                 :             :     bf_assert(payload && raw_payload);
     209                 :             : 
     210                 :             :     unsigned long ethertype;
     211                 :             :     char *endptr;
     212                 :             :     int r;
     213                 :             : 
     214                 :          79 :     r = bf_ethertype_from_str(raw_payload, payload);
     215         [ +  + ]:          79 :     if (!r)
     216                 :             :         return 0;
     217                 :             : 
     218                 :          34 :     ethertype = strtoul(raw_payload, &endptr, BF_BASE_10);
     219   [ +  +  +  + ]:          34 :     if (*endptr == '\0' && ethertype <= UINT16_MAX) {
     220                 :          14 :         *(uint16_t *)payload = (uint16_t)ethertype;
     221                 :          14 :         return 0;
     222                 :             :     }
     223                 :             : 
     224                 :          20 :     ethertype = strtoul(raw_payload, &endptr, BF_BASE_16);
     225   [ +  +  +  + ]:          20 :     if (*endptr == '\0' && ethertype <= UINT16_MAX) {
     226                 :          14 :         *(uint16_t *)payload = (uint16_t)ethertype;
     227                 :          14 :         return 0;
     228                 :             :     }
     229                 :             : 
     230         [ +  - ]:           6 :     bf_err(
     231                 :             :         "\"%s %s\" expects an internet layer protocol name (e.g. \"IPv6\", case insensitive), or a valid decimal or hexadecimal IEEE 802 number, not '%s'",
     232                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     233                 :             : 
     234                 :             :     return -EINVAL;
     235                 :             : }
     236                 :             : 
     237                 :           2 : void _bf_print_l3_proto(const void *payload)
     238                 :             : {
     239                 :             :     bf_assert(payload);
     240                 :             : 
     241                 :           2 :     const char *ethertype = bf_ethertype_to_str(*(uint16_t *)payload);
     242                 :             : 
     243         [ +  + ]:           2 :     if (ethertype)
     244                 :           1 :         (void)fprintf(stdout, "%s", ethertype);
     245                 :             :     else
     246                 :           1 :         (void)fprintf(stdout, "0x%04" PRIx16, *(uint16_t *)payload);
     247                 :           2 : }
     248                 :             : 
     249                 :         288 : int _bf_parse_l4_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     250                 :             :                        void *payload, const char *raw_payload)
     251                 :             : {
     252                 :             :     bf_assert(payload && raw_payload);
     253                 :             : 
     254                 :             :     unsigned long ipproto;
     255                 :             :     char *endptr;
     256                 :             :     int r;
     257                 :             : 
     258                 :         288 :     r = bf_ipproto_from_str(raw_payload, payload);
     259         [ +  + ]:         288 :     if (!r)
     260                 :             :         return 0;
     261                 :             : 
     262                 :          94 :     ipproto = strtoul(raw_payload, &endptr, BF_BASE_10);
     263   [ +  +  +  + ]:          94 :     if (*endptr == '\0' && ipproto <= UINT8_MAX) {
     264                 :          61 :         *(uint8_t *)payload = (uint8_t)ipproto;
     265                 :          61 :         return 0;
     266                 :             :     }
     267                 :             : 
     268         [ +  - ]:          33 :     bf_err(
     269                 :             :         "\"%s %s\" expects a transport layer protocol name (e.g. \"ICMP\", case insensitive), or a valid decimal internet protocol number, not '%s'",
     270                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     271                 :             : 
     272                 :             :     return -EINVAL;
     273                 :             : }
     274                 :             : 
     275                 :           7 : void _bf_print_l4_proto(const void *payload)
     276                 :             : {
     277                 :             :     bf_assert(payload);
     278                 :             : 
     279                 :           7 :     const char *ipproto = bf_ipproto_to_str(*(uint8_t *)payload);
     280                 :             : 
     281         [ +  + ]:           7 :     if (ipproto)
     282                 :           6 :         (void)fprintf(stdout, "%s", ipproto);
     283                 :             :     else
     284                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     285                 :           7 : }
     286                 :             : 
     287                 :         617 : int _bf_parse_l4_port(enum bf_matcher_type type, enum bf_matcher_op op,
     288                 :             :                       void *payload, const char *raw_payload)
     289                 :             : {
     290                 :             :     bf_assert(payload && raw_payload);
     291                 :             : 
     292                 :             :     unsigned long port;
     293                 :             :     char *endptr;
     294                 :             : 
     295                 :         617 :     port = strtoul(raw_payload, &endptr, BF_BASE_10);
     296   [ +  +  +  + ]:         617 :     if (*endptr == '\0' && port <= UINT16_MAX) {
     297                 :         556 :         *(uint16_t *)payload = htobe16((uint16_t)port);
     298                 :         556 :         return 0;
     299                 :             :     }
     300                 :             : 
     301         [ +  - ]:          61 :     bf_err("\"%s %s\" expects a valid decimal port number, not '%s'",
     302                 :             :            bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     303                 :             : 
     304                 :             :     return -EINVAL;
     305                 :             : }
     306                 :             : 
     307                 :           1 : void _bf_print_l4_port(const void *payload)
     308                 :             : {
     309                 :             :     bf_assert(payload);
     310                 :             : 
     311                 :           1 :     (void)fprintf(stdout, "%" PRIu16, (uint16_t)be16toh(*(uint16_t *)payload));
     312                 :           1 : }
     313                 :             : 
     314                 :             : #define BF_PORT_RANGE_MAX_LEN 16 // 65535-65535, with nul char, round to **2
     315                 :             : 
     316                 :         217 : static int _bf_parse_l4_port_range(enum bf_matcher_type type,
     317                 :             :                                    enum bf_matcher_op op, void *payload,
     318                 :             :                                    const char *raw_payload)
     319                 :             : {
     320                 :             :     bf_assert(payload && raw_payload);
     321                 :             : 
     322                 :             :     uint16_t *ports = (uint16_t *)payload;
     323                 :             :     unsigned long port;
     324                 :             :     char buf[BF_PORT_RANGE_MAX_LEN];
     325                 :             :     char *first;
     326                 :             :     char *second;
     327                 :             :     char *endptr;
     328                 :             : 
     329                 :         217 :     bf_strncpy(buf, BF_PORT_RANGE_MAX_LEN, raw_payload);
     330                 :             : 
     331         [ +  + ]:         217 :     if (!isdigit(*raw_payload))
     332                 :          25 :         goto err;
     333                 :             : 
     334                 :         192 :     first = strtok_r(buf, "-", &second);
     335         [ -  + ]:         192 :     if (!first)
     336                 :           0 :         goto err;
     337                 :             : 
     338         [ +  + ]:         192 :     if (!*second)
     339                 :          14 :         goto err;
     340                 :             : 
     341                 :         178 :     port = strtoul(first, &endptr, BF_BASE_10);
     342   [ +  +  +  + ]:         178 :     if (*endptr != '\0' || port > UINT16_MAX)
     343                 :          18 :         goto err;
     344                 :         160 :     ports[0] = (uint16_t)port;
     345                 :             : 
     346                 :         160 :     port = strtoul(second, &endptr, BF_BASE_10);
     347   [ +  -  +  + ]:         160 :     if (*endptr != '\0' || port > UINT16_MAX)
     348                 :           1 :         goto err;
     349                 :         159 :     ports[1] = (uint16_t)port;
     350                 :             : 
     351         [ +  + ]:         159 :     if (ports[1] < ports[0])
     352                 :           7 :         goto err;
     353                 :             : 
     354                 :             :     return 0;
     355                 :             : 
     356                 :          65 : err:
     357         [ +  - ]:          65 :     bf_err(
     358                 :             :         "\"%s %s\" expects two positive decimal port numbers as `$START-$END`, with `$START <= $END`, not '%s'",
     359                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     360                 :             : 
     361                 :             :     return -EINVAL;
     362                 :             : }
     363                 :             : 
     364                 :           1 : void _bf_print_l4_port_range(const void *payload)
     365                 :             : {
     366                 :             :     bf_assert(payload);
     367                 :             : 
     368                 :             :     uint16_t *ports = (uint16_t *)payload;
     369                 :             : 
     370                 :           1 :     (void)fprintf(stdout, "%" PRIu16 "-%" PRIu16, ports[0], ports[1]);
     371                 :           1 : }
     372                 :             : 
     373                 :          42 : static int _bf_parse_probability(enum bf_matcher_type type,
     374                 :             :                                  enum bf_matcher_op op, void *payload,
     375                 :             :                                  const char *raw_payload)
     376                 :             : {
     377                 :             :     bf_assert(payload && raw_payload);
     378                 :             : 
     379                 :             :     unsigned long proba;
     380                 :             :     char *endptr;
     381                 :             : 
     382                 :          42 :     proba = strtoul(raw_payload, &endptr, BF_BASE_10);
     383   [ +  +  +  -  :          42 :     if (endptr[0] == '%' && endptr[1] == '\0' && proba <= 100) {
                   +  + ]
     384                 :          37 :         *(uint8_t *)payload = (uint8_t)proba;
     385                 :          37 :         return 0;
     386                 :             :     }
     387                 :             : 
     388         [ +  - ]:           5 :     bf_err(
     389                 :             :         "\"%s %s\" expects a valid decimal percentage value (i.e., within [0%%, 100%%]), not '%s'",
     390                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     391                 :             : 
     392                 :             :     return -EINVAL;
     393                 :             : }
     394                 :             : 
     395                 :           1 : void _bf_print_probability(const void *payload)
     396                 :             : {
     397                 :             :     bf_assert(payload);
     398                 :             : 
     399                 :           1 :     (void)fprintf(stdout, "%" PRIu8 "%%", *(uint8_t *)payload);
     400                 :           1 : }
     401                 :             : 
     402                 :          34 : static int _bf_parse_mark(enum bf_matcher_type type, enum bf_matcher_op op,
     403                 :             :                           void *payload, const char *raw_payload)
     404                 :             : {
     405                 :             :     long long mark;
     406                 :             :     char *endptr;
     407                 :             : 
     408                 :             :     UNUSED(type);
     409                 :             :     UNUSED(op);
     410                 :             : 
     411                 :             :     bf_assert(payload);
     412                 :             :     bf_assert(raw_payload);
     413                 :             : 
     414                 :          34 :     mark = strtoll(raw_payload, &endptr, 0);
     415         [ +  + ]:          34 :     if (*endptr) {
     416         [ +  - ]:           3 :         return bf_err_r(-EINVAL,
     417                 :             :                         "mark value '%s' can't be parsed as a positive integer",
     418                 :             :                         raw_payload);
     419                 :             :     }
     420         [ +  + ]:          31 :     if (mark < 0) {
     421         [ +  - ]:           2 :         return bf_err_r(-EINVAL, "mark should be positive, not '%s'",
     422                 :             :                         raw_payload);
     423                 :             :     }
     424         [ +  + ]:          29 :     if (mark > UINT32_MAX)
     425         [ +  - ]:           2 :         return bf_err_r(-EINVAL, "mark should be at most 0x%x", UINT32_MAX);
     426                 :             : 
     427                 :          27 :     *(uint32_t *)payload = (uint32_t)mark;
     428                 :             : 
     429                 :          27 :     return 0;
     430                 :             : }
     431                 :             : 
     432                 :           1 : void _bf_print_mark(const void *payload)
     433                 :             : {
     434                 :             :     bf_assert(payload);
     435                 :             : 
     436                 :           1 :     (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
     437                 :           1 : }
     438                 :             : 
     439                 :         137 : static int _bf_parse_ipv4_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     440                 :             :                                void *payload, const char *raw_payload)
     441                 :             : {
     442                 :             :     bf_assert(payload && raw_payload);
     443                 :             : 
     444                 :             :     int r;
     445                 :             : 
     446                 :         137 :     r = inet_pton(AF_INET, raw_payload, payload);
     447         [ +  + ]:         137 :     if (r == 1)
     448                 :             :         return 0;
     449                 :             : 
     450         [ +  - ]:           6 :     bf_err(
     451                 :             :         "\"%s %s\" expects an IPv4 address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255, not '%s' ",
     452                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     453                 :             : 
     454                 :             :     return -EINVAL;
     455                 :             : }
     456                 :             : 
     457                 :           1 : void _bf_print_ipv4_addr(const void *payload)
     458                 :             : {
     459                 :             :     bf_assert(payload);
     460                 :             : 
     461                 :             :     char str[INET4_ADDRSTRLEN];
     462                 :             : 
     463         [ +  - ]:           1 :     if (inet_ntop(AF_INET, payload, str, INET4_ADDRSTRLEN))
     464                 :           1 :         (void)fprintf(stdout, "%s", str);
     465                 :             :     else
     466                 :           0 :         (void)fprintf(stdout, "<failed to print IPv4 address>");
     467                 :           1 : }
     468                 :             : 
     469                 :             : #define BF_IPV4_NET_MAX_LEN                                                    \
     470                 :             :     32 // 255.255.255.255/32, with nul char, round to **2
     471                 :             : 
     472                 :          89 : static int _bf_parse_ipv4_net(enum bf_matcher_type type, enum bf_matcher_op op,
     473                 :             :                               void *payload, const char *raw_payload)
     474                 :             : {
     475                 :             :     bf_assert(payload && raw_payload);
     476                 :             : 
     477                 :             :     struct bf_ip4_lpm_key *addr = payload;
     478                 :             :     char buf[BF_IPV4_NET_MAX_LEN];
     479                 :             :     char *strip, *strmask, *endptr;
     480                 :             :     int r;
     481                 :             : 
     482                 :          89 :     bf_strncpy(buf, BF_IPV4_NET_MAX_LEN, raw_payload);
     483                 :             : 
     484         [ +  + ]:          89 :     if (!isdigit(*raw_payload))
     485                 :           4 :         goto err;
     486                 :             : 
     487                 :          85 :     strip = strtok_r(buf, "/", &strmask);
     488   [ +  -  +  + ]:          85 :     if (!strip || !*strmask)
     489                 :           1 :         goto err;
     490                 :             : 
     491                 :          84 :     r = inet_pton(AF_INET, strip, &addr->data);
     492         [ +  + ]:          84 :     if (r != 1)
     493                 :           1 :         goto err;
     494                 :             : 
     495                 :          83 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     496   [ +  +  +  + ]:          83 :     if (*endptr != '\0' || addr->prefixlen > 32)
     497                 :          13 :         goto err;
     498                 :             : 
     499                 :             :     return 0;
     500                 :             : 
     501                 :          19 : err:
     502         [ +  - ]:          19 :     bf_err(
     503                 :             :         "\"%s %s\" expects an IPv4 network address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255 followed by a subnet mask (e.g., \"124.24.12.5/30\"), not '%s' ",
     504                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     505                 :             : 
     506                 :             :     return -EINVAL;
     507                 :             : }
     508                 :             : 
     509                 :           1 : void _bf_print_ipv4_net(const void *payload)
     510                 :             : {
     511                 :             :     bf_assert(payload);
     512                 :             : 
     513                 :             :     char str[INET4_ADDRSTRLEN];
     514                 :             :     const struct bf_ip4_lpm_key *addr = payload;
     515                 :             : 
     516         [ +  - ]:           1 :     if (inet_ntop(AF_INET, &addr->data, str, INET4_ADDRSTRLEN))
     517                 :           1 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     518                 :             :     else
     519                 :           0 :         (void)fprintf(stdout, "<failed to print IPv4 network>");
     520                 :           1 : }
     521                 :             : 
     522                 :         186 : static int _bf_parse_ipv6_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     523                 :             :                                void *payload, const char *raw_payload)
     524                 :             : {
     525                 :             :     bf_assert(payload && raw_payload);
     526                 :             : 
     527                 :             :     int r;
     528                 :             : 
     529                 :         186 :     r = inet_pton(AF_INET6, raw_payload, payload);
     530         [ +  + ]:         186 :     if (r == 1)
     531                 :             :         return 0;
     532                 :             : 
     533         [ +  - ]:          36 :     bf_err(
     534                 :             :         "\"%s %s\" expects an IPv6 address composed of 8 hexadecimal numbers (abbreviations are supported), not '%s' ",
     535                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     536                 :             : 
     537                 :             :     return -EINVAL;
     538                 :             : }
     539                 :             : 
     540                 :           1 : void _bf_print_ipv6_addr(const void *payload)
     541                 :             : {
     542                 :             :     bf_assert(payload);
     543                 :             : 
     544                 :             :     char str[INET6_ADDRSTRLEN];
     545                 :             : 
     546         [ +  - ]:           1 :     if (inet_ntop(AF_INET6, payload, str, INET6_ADDRSTRLEN))
     547                 :           1 :         (void)fprintf(stdout, "%s", str);
     548                 :             :     else
     549                 :           0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     550                 :           1 : }
     551                 :             : 
     552                 :             : #define BF_IPV6_NET_MAX_LEN (INET6_ADDRSTRLEN + 4)
     553                 :             : 
     554                 :         286 : static int _bf_parse_ipv6_net(enum bf_matcher_type type, enum bf_matcher_op op,
     555                 :             :                               void *payload, const char *raw_payload)
     556                 :             : {
     557                 :             :     bf_assert(payload && raw_payload);
     558                 :             : 
     559                 :             :     struct bf_ip6_lpm_key *addr = payload;
     560                 :             :     char buf[BF_IPV6_NET_MAX_LEN];
     561                 :             :     char *strip, *strmask, *endptr;
     562                 :             :     int r;
     563                 :             : 
     564                 :         286 :     bf_strncpy(buf, BF_IPV6_NET_MAX_LEN, raw_payload);
     565                 :             : 
     566   [ +  +  +  +  :         286 :     if (!isalpha(*raw_payload) && !isdigit(*raw_payload) && *raw_payload != ':')
                   +  + ]
     567                 :          12 :         goto err;
     568                 :             : 
     569                 :         274 :     strip = strtok_r(buf, "/", &strmask);
     570   [ +  -  +  + ]:         274 :     if (!strip || !*strmask)
     571                 :          29 :         goto err;
     572                 :             : 
     573                 :         245 :     r = inet_pton(AF_INET6, strip, &addr->data);
     574         [ +  + ]:         245 :     if (r != 1)
     575                 :          13 :         goto err;
     576                 :             : 
     577                 :         232 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     578   [ +  +  +  + ]:         232 :     if (*endptr != '\0' || addr->prefixlen > 128)
     579                 :          33 :         goto err;
     580                 :             : 
     581                 :             :     return 0;
     582                 :             : 
     583                 :          87 : err:
     584         [ +  - ]:          87 :     bf_err(
     585                 :             :         "\"%s %s\" expects an IPv6 network address composed of 8 hexadecimal numbers (abbreviations are supported) followed by a subnet mask (e.g., \"2001:db8:85a3::/48\"), not '%s' ",
     586                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     587                 :             : 
     588                 :             :     return -EINVAL;
     589                 :             : }
     590                 :             : 
     591                 :           1 : void _bf_print_ipv6_net(const void *payload)
     592                 :             : {
     593                 :             :     bf_assert(payload);
     594                 :             : 
     595                 :             :     const struct bf_ip6_lpm_key *addr = payload;
     596                 :             :     char str[INET6_ADDRSTRLEN];
     597                 :             : 
     598         [ +  - ]:           1 :     if (inet_ntop(AF_INET6, addr->data, str, INET6_ADDRSTRLEN))
     599                 :           1 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     600                 :             :     else
     601                 :           0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     602                 :           1 : }
     603                 :             : 
     604                 :         139 : static int _bf_parse_tcp_flags(enum bf_matcher_type type, enum bf_matcher_op op,
     605                 :             :                                void *payload, const char *raw_payload)
     606                 :             : {
     607                 :             :     bf_assert(payload && raw_payload);
     608                 :             : 
     609                 :             :     _cleanup_free_ char *_raw_payload = NULL;
     610                 :             :     char *tmp;
     611                 :             :     char *saveptr;
     612                 :             :     char *token;
     613                 :             :     uint8_t *flags = payload;
     614                 :             : 
     615                 :         139 :     _raw_payload = strdup(raw_payload);
     616                 :             :     if (!raw_payload)
     617                 :             :         goto err;
     618                 :             : 
     619                 :         139 :     *flags = 0;
     620                 :             :     tmp = _raw_payload;
     621                 :             : 
     622         [ +  + ]:         436 :     while ((token = strtok_r(tmp, ",", &saveptr))) {
     623                 :             :         enum bf_tcp_flag new_flag;
     624                 :             :         int r;
     625                 :             : 
     626                 :         306 :         r = bf_tcp_flag_from_str(token, &new_flag);
     627         [ +  + ]:         306 :         if (r)
     628                 :           9 :             goto err;
     629                 :             : 
     630                 :         297 :         *flags |= (uint8_t)(1 << new_flag);
     631                 :             : 
     632                 :             :         tmp = NULL;
     633                 :             :     }
     634                 :             : 
     635                 :             :     return 0;
     636                 :             : 
     637                 :             : err:
     638         [ +  - ]:           9 :     bf_err(
     639                 :             :         "\"%s %s\" expects a comma-separated list of one or more TCP flags (fin, syn, rst, psh, ack, urg, ece, or cwr), not '%s' ",
     640                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     641                 :             : 
     642                 :             :     return -EINVAL;
     643                 :             : }
     644                 :             : 
     645                 :           1 : void _bf_print_tcp_flags(const void *payload)
     646                 :             : {
     647                 :             :     bf_assert(payload);
     648                 :             : 
     649                 :           1 :     uint8_t flag = *(uint8_t *)payload;
     650                 :             : 
     651         [ +  + ]:           9 :     for (uint32_t i = 0; i < _BF_TCP_MAX; ++i) {
     652         [ +  + ]:           8 :         if (flag & (1 << i)) {
     653                 :           2 :             flag &= ~(1 << i);
     654         [ +  + ]:           3 :             (void)fprintf(stdout, "%s%s", bf_tcp_flag_to_str(i),
     655                 :             :                           flag ? "," : "");
     656                 :             :         }
     657                 :             :     }
     658                 :           1 : }
     659                 :             : 
     660                 :          86 : static int _bf_parse_icmp_type(enum bf_matcher_type type, enum bf_matcher_op op,
     661                 :             :                                void *payload, const char *raw_payload)
     662                 :             : {
     663                 :             :     bf_assert(payload && raw_payload);
     664                 :             : 
     665                 :             :     unsigned long icmptype;
     666                 :             :     char *endptr;
     667                 :             :     int r;
     668                 :             : 
     669                 :          86 :     r = bf_icmp_type_from_str(raw_payload, payload);
     670         [ +  + ]:          86 :     if (!r)
     671                 :             :         return 0;
     672                 :             : 
     673                 :          56 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
     674                 :             : 
     675   [ +  +  +  + ]:          56 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     676                 :          22 :         *(uint8_t *)payload = (uint8_t)icmptype;
     677                 :          22 :         return 0;
     678                 :             :     }
     679                 :             : 
     680                 :          34 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
     681   [ +  +  +  + ]:          34 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     682                 :          22 :         *(uint8_t *)payload = (uint8_t)icmptype;
     683                 :          22 :         return 0;
     684                 :             :     }
     685                 :             : 
     686         [ +  - ]:          12 :     bf_err(
     687                 :             :         "\"%s %s\" expects an ICMP type name (e.g. \"echo-reply\", case insensitive), or or a decimal or hexadecimal ICMP type value, not '%s'",
     688                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     689                 :             : 
     690                 :             :     return -EINVAL;
     691                 :             : }
     692                 :             : 
     693                 :           4 : void _bf_print_icmp_type(const void *payload)
     694                 :             : {
     695                 :             :     bf_assert(payload);
     696                 :             : 
     697                 :           4 :     const char *type = bf_icmp_type_to_str(*(uint8_t *)payload);
     698                 :             : 
     699         [ +  + ]:           4 :     if (type)
     700                 :           3 :         (void)fprintf(stdout, "%s", type);
     701                 :             :     else
     702                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     703                 :           4 : }
     704                 :             : 
     705                 :         160 : static int _bf_parse_icmp_code(enum bf_matcher_type type, enum bf_matcher_op op,
     706                 :             :                                void *payload, const char *raw_payload)
     707                 :             : {
     708                 :             :     bf_assert(payload && raw_payload);
     709                 :             : 
     710                 :             :     unsigned long code;
     711                 :             :     char *endptr;
     712                 :             : 
     713                 :         160 :     code = strtoul(raw_payload, &endptr, BF_BASE_10);
     714   [ +  +  +  + ]:         160 :     if (*endptr == '\0' && code <= UINT8_MAX) {
     715                 :          82 :         *(uint8_t *)payload = (uint8_t)code;
     716                 :          82 :         return 0;
     717                 :             :     }
     718                 :             : 
     719                 :          78 :     code = strtoul(raw_payload, &endptr, BF_BASE_16);
     720   [ +  +  +  + ]:          78 :     if (*endptr == '\0' && code <= UINT8_MAX) {
     721                 :          54 :         *(uint8_t *)payload = (uint8_t)code;
     722                 :          54 :         return 0;
     723                 :             :     }
     724                 :             : 
     725         [ +  - ]:          24 :     bf_err(
     726                 :             :         "\"%s %s\" expects a decimal or hexadecimal ICMP or ICMPv6 code value, not '%s'",
     727                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     728                 :             : 
     729                 :             :     return -EINVAL;
     730                 :             : }
     731                 :             : 
     732                 :           3 : void _bf_print_icmp_code(const void *payload)
     733                 :             : {
     734                 :             :     bf_assert(payload);
     735                 :             : 
     736                 :           3 :     (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     737                 :           3 : }
     738                 :             : 
     739                 :          94 : static int _bf_parse_icmpv6_type(enum bf_matcher_type type,
     740                 :             :                                  enum bf_matcher_op op, void *payload,
     741                 :             :                                  const char *raw_payload)
     742                 :             : {
     743                 :             :     bf_assert(payload && raw_payload);
     744                 :             : 
     745                 :             :     unsigned long icmptype;
     746                 :             :     char *endptr;
     747                 :             :     int r;
     748                 :             : 
     749                 :          94 :     r = bf_icmpv6_type_from_str(raw_payload, payload);
     750         [ +  + ]:          94 :     if (!r)
     751                 :             :         return 0;
     752                 :             : 
     753                 :          58 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
     754                 :             : 
     755   [ +  +  +  + ]:          58 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     756                 :          23 :         *(uint8_t *)payload = (uint8_t)icmptype;
     757                 :          23 :         return 0;
     758                 :             :     }
     759                 :             : 
     760                 :          35 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
     761   [ +  +  +  + ]:          35 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     762                 :          23 :         *(uint8_t *)payload = (uint8_t)icmptype;
     763                 :          23 :         return 0;
     764                 :             :     }
     765                 :             : 
     766         [ +  - ]:          12 :     bf_err(
     767                 :             :         "\"%s %s\" expects an ICMPv6 type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMPv6 type value, not '%s'",
     768                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     769                 :             : 
     770                 :             :     return -EINVAL;
     771                 :             : }
     772                 :             : 
     773                 :           2 : void _bf_print_icmpv6_type(const void *payload)
     774                 :             : {
     775                 :             :     bf_assert(payload);
     776                 :             : 
     777                 :           2 :     const char *type = bf_icmpv6_type_to_str(*(uint8_t *)payload);
     778                 :             : 
     779         [ +  + ]:           2 :     if (type)
     780                 :           1 :         (void)fprintf(stdout, "%s", type);
     781                 :             :     else
     782                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     783                 :           2 : }
     784                 :             : 
     785                 :             : #define BF_MATCHER_OPS(op, payload_size, parse_cb, print_cb)                   \
     786                 :             :     [op] = {payload_size, parse_cb, print_cb}
     787                 :             : 
     788                 :             : #define _BF_TCP_FLAGS_OFFSET 13
     789                 :             : 
     790                 :             : static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
     791                 :             :     [BF_MATCHER_META_IFACE] =
     792                 :             :         {
     793                 :             :             .layer = BF_MATCHER_NO_LAYER,
     794                 :             :             .ops =
     795                 :             :                 {
     796                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     797                 :             :                                    _bf_parse_iface, _bf_print_iface),
     798                 :             :                 },
     799                 :             :         },
     800                 :             :     [BF_MATCHER_META_L3_PROTO] =
     801                 :             :         {
     802                 :             :             .layer = BF_MATCHER_NO_LAYER,
     803                 :             :             .ops =
     804                 :             :                 {
     805                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     806                 :             :                                    _bf_parse_l3_proto, _bf_print_l3_proto),
     807                 :             :                 },
     808                 :             :         },
     809                 :             :     [BF_MATCHER_META_L4_PROTO] =
     810                 :             :         {
     811                 :             :             .layer = BF_MATCHER_NO_LAYER,
     812                 :             :             .ops =
     813                 :             :                 {
     814                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     815                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     816                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     817                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     818                 :             :                 },
     819                 :             :         },
     820                 :             :     [BF_MATCHER_META_SPORT] =
     821                 :             :         {
     822                 :             :             .layer = BF_MATCHER_NO_LAYER,
     823                 :             :             .ops =
     824                 :             :                 {
     825                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     826                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     827                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     828                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     829                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     830                 :             :                                    _bf_parse_l4_port_range,
     831                 :             :                                    _bf_print_l4_port_range),
     832                 :             :                 },
     833                 :             :         },
     834                 :             :     [BF_MATCHER_META_DPORT] =
     835                 :             :         {
     836                 :             :             .layer = BF_MATCHER_NO_LAYER,
     837                 :             :             .ops =
     838                 :             :                 {
     839                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     840                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     841                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     842                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     843                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     844                 :             :                                    _bf_parse_l4_port_range,
     845                 :             :                                    _bf_print_l4_port_range),
     846                 :             :                 },
     847                 :             :         },
     848                 :             :     [BF_MATCHER_META_PROBABILITY] =
     849                 :             :         {
     850                 :             :             .layer = BF_MATCHER_NO_LAYER,
     851                 :             :             .ops =
     852                 :             :                 {
     853                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     854                 :             :                                    _bf_parse_probability,
     855                 :             :                                    _bf_print_probability),
     856                 :             :                 },
     857                 :             :         },
     858                 :             :     [BF_MATCHER_META_MARK] =
     859                 :             :         {
     860                 :             :             .layer = BF_MATCHER_NO_LAYER,
     861                 :             :             .unsupported_hooks = BF_FLAGS(BF_HOOK_XDP),
     862                 :             :             .ops =
     863                 :             :                 {
     864                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     865                 :             :                                    _bf_parse_mark, _bf_print_mark),
     866                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     867                 :             :                                    _bf_parse_mark, _bf_print_mark),
     868                 :             :                 },
     869                 :             :         },
     870                 :             :     [BF_MATCHER_META_FLOW_HASH] =
     871                 :             :         {
     872                 :             :             .layer = BF_MATCHER_NO_LAYER,
     873                 :             :             .unsupported_hooks = BF_FLAGS(
     874                 :             :                 BF_HOOK_XDP, BF_HOOK_CGROUP_INGRESS, BF_HOOK_CGROUP_EGRESS,
     875                 :             :                 BF_HOOK_NF_FORWARD, BF_HOOK_NF_LOCAL_IN, BF_HOOK_NF_LOCAL_OUT,
     876                 :             :                 BF_HOOK_NF_POST_ROUTING, BF_HOOK_NF_PRE_ROUTING),
     877                 :             :             .ops =
     878                 :             :                 {
     879                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     880                 :             :                                    _bf_parse_int, _bf_print_int),
     881                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     882                 :             :                                    _bf_parse_int, _bf_print_int),
     883                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint32_t),
     884                 :             :                                    _bf_parse_int_range, _bf_print_int_range),
     885                 :             :                 },
     886                 :             :         },
     887                 :             :     [BF_MATCHER_IP4_SADDR] =
     888                 :             :         {
     889                 :             :             .layer = BF_MATCHER_LAYER_3,
     890                 :             :             .hdr_id = ETH_P_IP,
     891                 :             :             .hdr_payload_size = sizeof(uint32_t),
     892                 :             :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
     893                 :             :             .ops =
     894                 :             :                 {
     895                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     896                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     897                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     898                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     899                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
     900                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     901                 :             :                 },
     902                 :             :         },
     903                 :             :     [BF_MATCHER_IP4_DADDR] =
     904                 :             :         {
     905                 :             :             .layer = BF_MATCHER_LAYER_3,
     906                 :             :             .hdr_id = ETH_P_IP,
     907                 :             :             .hdr_payload_size = sizeof(uint32_t),
     908                 :             :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
     909                 :             :             .ops =
     910                 :             :                 {
     911                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     912                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     913                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     914                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     915                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
     916                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     917                 :             :                 },
     918                 :             :         },
     919                 :             :     [BF_MATCHER_IP4_SNET] =
     920                 :             :         {
     921                 :             :             .layer = BF_MATCHER_LAYER_3,
     922                 :             :             .hdr_id = ETH_P_IP,
     923                 :             :             .hdr_payload_size = sizeof(uint32_t),
     924                 :             :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
     925                 :             :             .ops =
     926                 :             :                 {
     927                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
     928                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     929                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
     930                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     931                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
     932                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     933                 :             :                 },
     934                 :             :         },
     935                 :             :     [BF_MATCHER_IP4_DNET] =
     936                 :             :         {
     937                 :             :             .layer = BF_MATCHER_LAYER_3,
     938                 :             :             .hdr_id = ETH_P_IP,
     939                 :             :             .hdr_payload_size = sizeof(uint32_t),
     940                 :             :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
     941                 :             :             .ops =
     942                 :             :                 {
     943                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
     944                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     945                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
     946                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     947                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
     948                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     949                 :             :                 },
     950                 :             :         },
     951                 :             :     [BF_MATCHER_IP4_PROTO] =
     952                 :             :         {
     953                 :             :             .layer = BF_MATCHER_LAYER_3,
     954                 :             :             .hdr_id = ETH_P_IP,
     955                 :             :             .hdr_payload_size = sizeof(uint8_t),
     956                 :             :             .hdr_payload_offset = offsetof(struct iphdr, protocol),
     957                 :             :             .ops =
     958                 :             :                 {
     959                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     960                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     961                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
     962                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     963                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
     964                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     965                 :             :                 },
     966                 :             :         },
     967                 :             :     [BF_MATCHER_IP6_SADDR] =
     968                 :             :         {
     969                 :             :             .layer = BF_MATCHER_LAYER_3,
     970                 :             :             .hdr_id = ETH_P_IPV6,
     971                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
     972                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
     973                 :             :             .ops =
     974                 :             :                 {
     975                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
     976                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     977                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
     978                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     979                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
     980                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     981                 :             :                 },
     982                 :             :         },
     983                 :             :     [BF_MATCHER_IP6_DADDR] =
     984                 :             :         {
     985                 :             :             .layer = BF_MATCHER_LAYER_3,
     986                 :             :             .hdr_id = ETH_P_IPV6,
     987                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
     988                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
     989                 :             :             .ops =
     990                 :             :                 {
     991                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
     992                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     993                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
     994                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     995                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
     996                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     997                 :             :                 },
     998                 :             :         },
     999                 :             :     [BF_MATCHER_IP6_SNET] =
    1000                 :             :         {
    1001                 :             :             .layer = BF_MATCHER_LAYER_3,
    1002                 :             :             .hdr_id = ETH_P_IPV6,
    1003                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1004                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
    1005                 :             :             .ops =
    1006                 :             :                 {
    1007                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
    1008                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1009                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
    1010                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1011                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
    1012                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1013                 :             :                 },
    1014                 :             :         },
    1015                 :             :     [BF_MATCHER_IP6_DNET] =
    1016                 :             :         {
    1017                 :             :             .layer = BF_MATCHER_LAYER_3,
    1018                 :             :             .hdr_id = ETH_P_IPV6,
    1019                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1020                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
    1021                 :             :             .ops =
    1022                 :             :                 {
    1023                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
    1024                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1025                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
    1026                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1027                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
    1028                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1029                 :             :                 },
    1030                 :             :         },
    1031                 :             :     [BF_MATCHER_IP6_NEXTHDR] =
    1032                 :             :         {
    1033                 :             :             .layer = BF_MATCHER_LAYER_3,
    1034                 :             :             .hdr_id = ETH_P_IPV6,
    1035                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1036                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, nexthdr),
    1037                 :             :             .ops =
    1038                 :             :                 {
    1039                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1040                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1041                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1042                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1043                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1044                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1045                 :             :                 },
    1046                 :             :         },
    1047                 :             :     [BF_MATCHER_TCP_SPORT] =
    1048                 :             :         {
    1049                 :             :             .layer = BF_MATCHER_LAYER_4,
    1050                 :             :             .hdr_id = IPPROTO_TCP,
    1051                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1052                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, source),
    1053                 :             :             .ops =
    1054                 :             :                 {
    1055                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1056                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1057                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
    1058                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1059                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1060                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1061                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1062                 :             :                                    _bf_parse_l4_port_range,
    1063                 :             :                                    _bf_print_l4_port_range),
    1064                 :             :                 },
    1065                 :             :         },
    1066                 :             :     [BF_MATCHER_TCP_DPORT] =
    1067                 :             :         {
    1068                 :             :             .layer = BF_MATCHER_LAYER_4,
    1069                 :             :             .hdr_id = IPPROTO_TCP,
    1070                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1071                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, dest),
    1072                 :             :             .ops =
    1073                 :             :                 {
    1074                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1075                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1076                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
    1077                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1078                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1079                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1080                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1081                 :             :                                    _bf_parse_l4_port_range,
    1082                 :             :                                    _bf_print_l4_port_range),
    1083                 :             :                 },
    1084                 :             :         },
    1085                 :             :     [BF_MATCHER_TCP_FLAGS] =
    1086                 :             :         {
    1087                 :             :             .layer = BF_MATCHER_LAYER_4,
    1088                 :             :             .hdr_id = IPPROTO_TCP,
    1089                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1090                 :             :             .hdr_payload_offset = _BF_TCP_FLAGS_OFFSET,
    1091                 :             :             .ops =
    1092                 :             :                 {
    1093                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1094                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1095                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1096                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1097                 :             :                     BF_MATCHER_OPS(BF_MATCHER_ANY, sizeof(uint8_t),
    1098                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1099                 :             :                     BF_MATCHER_OPS(BF_MATCHER_ALL, sizeof(uint8_t),
    1100                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1101                 :             :                 },
    1102                 :             :         },
    1103                 :             :     [BF_MATCHER_UDP_SPORT] =
    1104                 :             :         {
    1105                 :             :             .layer = BF_MATCHER_LAYER_4,
    1106                 :             :             .hdr_id = IPPROTO_UDP,
    1107                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1108                 :             :             .hdr_payload_offset = offsetof(struct udphdr, source),
    1109                 :             :             .ops =
    1110                 :             :                 {
    1111                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1112                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1113                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
    1114                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1115                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1116                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1117                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1118                 :             :                                    _bf_parse_l4_port_range,
    1119                 :             :                                    _bf_print_l4_port_range),
    1120                 :             :                 },
    1121                 :             :         },
    1122                 :             :     [BF_MATCHER_UDP_DPORT] =
    1123                 :             :         {
    1124                 :             :             .layer = BF_MATCHER_LAYER_4,
    1125                 :             :             .hdr_id = IPPROTO_UDP,
    1126                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1127                 :             :             .hdr_payload_offset = offsetof(struct udphdr, dest),
    1128                 :             :             .ops =
    1129                 :             :                 {
    1130                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1131                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1132                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
    1133                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1134                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1135                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1136                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1137                 :             :                                    _bf_parse_l4_port_range,
    1138                 :             :                                    _bf_print_l4_port_range),
    1139                 :             :                 },
    1140                 :             :         },
    1141                 :             :     [BF_MATCHER_ICMP_TYPE] =
    1142                 :             :         {
    1143                 :             :             .layer = BF_MATCHER_LAYER_4,
    1144                 :             :             .hdr_id = IPPROTO_ICMP,
    1145                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1146                 :             :             .hdr_payload_offset = offsetof(struct icmphdr, type),
    1147                 :             :             .ops =
    1148                 :             :                 {
    1149                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1150                 :             :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1151                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1152                 :             :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1153                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1154                 :             :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1155                 :             :                 },
    1156                 :             :         },
    1157                 :             :     [BF_MATCHER_ICMP_CODE] =
    1158                 :             :         {
    1159                 :             :             .layer = BF_MATCHER_LAYER_4,
    1160                 :             :             .hdr_id = IPPROTO_ICMP,
    1161                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1162                 :             :             .hdr_payload_offset = offsetof(struct icmphdr, code),
    1163                 :             :             .ops =
    1164                 :             :                 {
    1165                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1166                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1167                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1168                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1169                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1170                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1171                 :             :                 },
    1172                 :             :         },
    1173                 :             :     [BF_MATCHER_ICMPV6_TYPE] =
    1174                 :             :         {
    1175                 :             :             .layer = BF_MATCHER_LAYER_4,
    1176                 :             :             .hdr_id = IPPROTO_ICMPV6,
    1177                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1178                 :             :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_type),
    1179                 :             :             .ops =
    1180                 :             :                 {
    1181                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1182                 :             :                                    _bf_parse_icmpv6_type,
    1183                 :             :                                    _bf_print_icmpv6_type),
    1184                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1185                 :             :                                    _bf_parse_icmpv6_type,
    1186                 :             :                                    _bf_print_icmpv6_type),
    1187                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1188                 :             :                                    _bf_parse_icmpv6_type,
    1189                 :             :                                    _bf_print_icmpv6_type),
    1190                 :             :                 },
    1191                 :             :         },
    1192                 :             :     [BF_MATCHER_ICMPV6_CODE] =
    1193                 :             :         {
    1194                 :             :             .layer = BF_MATCHER_LAYER_4,
    1195                 :             :             .hdr_id = IPPROTO_ICMPV6,
    1196                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1197                 :             :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_code),
    1198                 :             :             .ops =
    1199                 :             :                 {
    1200                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1201                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1202                 :             :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1203                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1204                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1205                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1206                 :             :                 },
    1207                 :             :         },
    1208                 :             : };
    1209                 :             : 
    1210                 :        6425 : const struct bf_matcher_meta *bf_matcher_get_meta(enum bf_matcher_type type)
    1211                 :             : {
    1212         [ +  - ]:        6425 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1213                 :             :         return NULL;
    1214                 :             : 
    1215                 :        6425 :     return _bf_matcher_metas[type].layer == _BF_MATCHER_LAYER_UNDEFINED ?
    1216         [ +  + ]:        6425 :                NULL :
    1217                 :             :                &_bf_matcher_metas[type];
    1218                 :             : }
    1219                 :             : 
    1220                 :        3073 : const struct bf_matcher_ops *bf_matcher_get_ops(enum bf_matcher_type type,
    1221                 :             :                                                 enum bf_matcher_op op)
    1222                 :             : {
    1223                 :        3073 :     const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
    1224                 :             : 
    1225         [ +  + ]:        3073 :     if (!meta)
    1226                 :             :         return NULL;
    1227                 :             : 
    1228         [ +  + ]:        3067 :     return meta->ops[op].ref_payload_size ? &meta->ops[op] : NULL;
    1229                 :             : }
    1230                 :             : 
    1231                 :        1650 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
    1232                 :             :                    enum bf_matcher_op op, const void *payload,
    1233                 :             :                    size_t payload_len)
    1234                 :             : {
    1235                 :        1650 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1236                 :             : 
    1237                 :             :     bf_assert(matcher);
    1238                 :             :     bf_assert((payload && payload_len) || (!payload && !payload_len));
    1239                 :             : 
    1240                 :        1650 :     _matcher = malloc(sizeof(struct bf_matcher) + payload_len);
    1241         [ +  - ]:        1650 :     if (!_matcher)
    1242                 :             :         return -ENOMEM;
    1243                 :             : 
    1244                 :        1650 :     _matcher->type = type;
    1245                 :        1650 :     _matcher->op = op;
    1246                 :        1650 :     _matcher->len = sizeof(struct bf_matcher) + payload_len;
    1247                 :        1650 :     bf_memcpy(_matcher->payload, payload, payload_len);
    1248                 :             : 
    1249                 :        1650 :     *matcher = TAKE_PTR(_matcher);
    1250                 :             : 
    1251                 :        1650 :     return 0;
    1252                 :             : }
    1253                 :             : 
    1254                 :        2228 : int bf_matcher_new_from_raw(struct bf_matcher **matcher,
    1255                 :             :                             enum bf_matcher_type type, enum bf_matcher_op op,
    1256                 :             :                             const char *payload)
    1257                 :             : {
    1258                 :        2228 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1259                 :             :     const struct bf_matcher_ops *ops;
    1260                 :             :     int r;
    1261                 :             : 
    1262                 :             :     bf_assert(matcher && payload);
    1263                 :             : 
    1264                 :        2228 :     ops = bf_matcher_get_ops(type, op);
    1265         [ -  + ]:        2228 :     if (!ops) {
    1266         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "payload ops not found for '%s %s'",
    1267                 :             :                         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op));
    1268                 :             :     }
    1269                 :             : 
    1270                 :        2228 :     _matcher = malloc(sizeof(*_matcher) + ops->ref_payload_size);
    1271         [ +  - ]:        2228 :     if (!_matcher)
    1272                 :             :         return -ENOMEM;
    1273                 :             : 
    1274                 :        2228 :     _matcher->type = type;
    1275                 :        2228 :     _matcher->op = op;
    1276                 :        2228 :     _matcher->len = sizeof(*_matcher) + ops->ref_payload_size;
    1277                 :             : 
    1278                 :        2228 :     r = ops->parse(_matcher->type, _matcher->op, &_matcher->payload, payload);
    1279         [ +  + ]:        2228 :     if (r)
    1280                 :             :         return r;
    1281                 :             : 
    1282                 :        1824 :     *matcher = TAKE_PTR(_matcher);
    1283                 :             : 
    1284                 :        1824 :     return 0;
    1285                 :             : }
    1286                 :             : 
    1287                 :        1478 : int bf_matcher_new_from_pack(struct bf_matcher **matcher, bf_rpack_node_t node)
    1288                 :             : {
    1289                 :        1478 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1290                 :             :     enum bf_matcher_type type;
    1291                 :             :     enum bf_matcher_op op;
    1292                 :             :     const void *payload;
    1293                 :             :     size_t payload_len;
    1294                 :             :     int r;
    1295                 :             : 
    1296                 :             :     bf_assert(matcher);
    1297                 :             : 
    1298         [ -  + ]:        1478 :     r = bf_rpack_kv_enum(node, "type", &type);
    1299                 :             :     if (r)
    1300         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_matcher.type");
    1301                 :             : 
    1302         [ -  + ]:        1478 :     r = bf_rpack_kv_enum(node, "op", &op);
    1303                 :             :     if (r)
    1304         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_matcher.op");
    1305                 :             : 
    1306                 :        1478 :     r = bf_rpack_kv_bin(node, "payload", &payload, &payload_len);
    1307         [ -  + ]:        1478 :     if (r)
    1308         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_matcher.payload");
    1309                 :             : 
    1310                 :        1478 :     r = bf_matcher_new(&_matcher, type, op, payload, payload_len);
    1311         [ -  + ]:        1478 :     if (r)
    1312         [ #  # ]:           0 :         return bf_err_r(r, "failed to create bf_matcher from pack");
    1313                 :             : 
    1314                 :        1478 :     *matcher = TAKE_PTR(_matcher);
    1315                 :             : 
    1316                 :        1478 :     return 0;
    1317                 :             : }
    1318                 :             : 
    1319                 :       14468 : void bf_matcher_free(struct bf_matcher **matcher)
    1320                 :             : {
    1321                 :             :     bf_assert(matcher);
    1322                 :             : 
    1323         [ +  + ]:       14468 :     if (!*matcher)
    1324                 :             :         return;
    1325                 :             : 
    1326                 :        3878 :     free(*matcher);
    1327                 :        3878 :     *matcher = NULL;
    1328                 :             : }
    1329                 :             : 
    1330                 :        9334 : int bf_matcher_pack(const struct bf_matcher *matcher, bf_wpack_t *pack)
    1331                 :             : {
    1332                 :             :     bf_assert(matcher);
    1333                 :             :     bf_assert(pack);
    1334                 :             : 
    1335                 :        9334 :     bf_wpack_kv_int(pack, "type", matcher->type);
    1336                 :        9334 :     bf_wpack_kv_int(pack, "op", matcher->op);
    1337                 :        9334 :     bf_wpack_kv_bin(pack, "payload", matcher->payload,
    1338                 :        9334 :                     matcher->len - sizeof(*matcher));
    1339                 :             : 
    1340         [ -  + ]:        9334 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
    1341                 :             : }
    1342                 :             : 
    1343                 :          87 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
    1344                 :             : {
    1345                 :             :     bf_assert(matcher);
    1346                 :             :     bf_assert(prefix);
    1347                 :             : 
    1348         [ +  + ]:          87 :     DUMP(prefix, "struct bf_matcher at %p", matcher);
    1349                 :             : 
    1350                 :          87 :     bf_dump_prefix_push(prefix);
    1351                 :             : 
    1352         [ +  + ]:          87 :     DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
    1353         [ +  + ]:          87 :     DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
    1354         [ +  + ]:          87 :     DUMP(prefix, "len: %ld", matcher->len);
    1355         [ +  + ]:          87 :     DUMP(bf_dump_prefix_last(prefix), "payload:");
    1356                 :          87 :     bf_dump_prefix_push(prefix);
    1357                 :          87 :     bf_dump_hex(prefix, matcher->payload,
    1358                 :          87 :                 matcher->len - sizeof(struct bf_matcher));
    1359                 :          87 :     bf_dump_prefix_pop(prefix);
    1360                 :             : 
    1361                 :          87 :     bf_dump_prefix_pop(prefix);
    1362                 :          87 : }
    1363                 :             : 
    1364                 :       13946 : enum bf_matcher_type bf_matcher_get_type(const struct bf_matcher *matcher)
    1365                 :             : {
    1366                 :             :     bf_assert(matcher);
    1367                 :       13946 :     return matcher->type;
    1368                 :             : }
    1369                 :             : 
    1370                 :        1395 : enum bf_matcher_op bf_matcher_get_op(const struct bf_matcher *matcher)
    1371                 :             : {
    1372                 :             :     bf_assert(matcher);
    1373                 :        1395 :     return matcher->op;
    1374                 :             : }
    1375                 :             : 
    1376                 :        1628 : const void *bf_matcher_payload(const struct bf_matcher *matcher)
    1377                 :             : {
    1378                 :             :     bf_assert(matcher);
    1379                 :        1628 :     return matcher->payload;
    1380                 :             : }
    1381                 :             : 
    1382                 :          43 : size_t bf_matcher_payload_len(const struct bf_matcher *matcher)
    1383                 :             : {
    1384                 :             :     bf_assert(matcher);
    1385                 :          43 :     return matcher->len - sizeof(*matcher);
    1386                 :             : }
    1387                 :             : 
    1388                 :           1 : size_t bf_matcher_len(const struct bf_matcher *matcher)
    1389                 :             : {
    1390                 :             :     bf_assert(matcher);
    1391                 :           1 :     return matcher->len;
    1392                 :             : }
    1393                 :             : 
    1394                 :             : static const char *_bf_matcher_type_strs[] = {
    1395                 :             :     [BF_MATCHER_META_IFACE] = "meta.iface",
    1396                 :             :     [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
    1397                 :             :     [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
    1398                 :             :     [BF_MATCHER_META_PROBABILITY] = "meta.probability",
    1399                 :             :     [BF_MATCHER_META_SPORT] = "meta.sport",
    1400                 :             :     [BF_MATCHER_META_DPORT] = "meta.dport",
    1401                 :             :     [BF_MATCHER_META_MARK] = "meta.mark",
    1402                 :             :     [BF_MATCHER_META_FLOW_HASH] = "meta.flow_hash",
    1403                 :             :     [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
    1404                 :             :     [BF_MATCHER_IP4_SNET] = "ip4.snet",
    1405                 :             :     [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
    1406                 :             :     [BF_MATCHER_IP4_DNET] = "ip4.dnet",
    1407                 :             :     [BF_MATCHER_IP4_PROTO] = "ip4.proto",
    1408                 :             :     [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
    1409                 :             :     [BF_MATCHER_IP6_SNET] = "ip6.snet",
    1410                 :             :     [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
    1411                 :             :     [BF_MATCHER_IP6_DNET] = "ip6.dnet",
    1412                 :             :     [BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
    1413                 :             :     [BF_MATCHER_TCP_SPORT] = "tcp.sport",
    1414                 :             :     [BF_MATCHER_TCP_DPORT] = "tcp.dport",
    1415                 :             :     [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
    1416                 :             :     [BF_MATCHER_UDP_SPORT] = "udp.sport",
    1417                 :             :     [BF_MATCHER_UDP_DPORT] = "udp.dport",
    1418                 :             :     [BF_MATCHER_ICMP_TYPE] = "icmp.type",
    1419                 :             :     [BF_MATCHER_ICMP_CODE] = "icmp.code",
    1420                 :             :     [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
    1421                 :             :     [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
    1422                 :             :     [BF_MATCHER_SET] = "<set>",
    1423                 :             : };
    1424                 :             : 
    1425                 :             : static_assert(ARRAY_SIZE(_bf_matcher_type_strs) == _BF_MATCHER_TYPE_MAX,
    1426                 :             :               "missing entries in the matcher type array");
    1427                 :             : 
    1428                 :         478 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
    1429                 :             : {
    1430         [ +  - ]:         478 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1431                 :             :         return "<invalid>";
    1432                 :             : 
    1433                 :         478 :     return _bf_matcher_type_strs[type];
    1434                 :             : }
    1435                 :             : 
    1436                 :        2371 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
    1437                 :             : {
    1438                 :             :     bf_assert(str);
    1439                 :             :     bf_assert(type);
    1440                 :             : 
    1441         [ +  + ]:       36297 :     for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
    1442         [ +  + ]:       36292 :         if (bf_streq(_bf_matcher_type_strs[i], str)) {
    1443                 :        2366 :             *type = i;
    1444                 :        2366 :             return 0;
    1445                 :             :         }
    1446                 :             :     }
    1447                 :             : 
    1448                 :             :     return -EINVAL;
    1449                 :             : }
    1450                 :             : 
    1451                 :             : static const char *_bf_matcher_ops_strs[] = {
    1452                 :             :     [BF_MATCHER_EQ] = "eq",   [BF_MATCHER_NE] = "not",
    1453                 :             :     [BF_MATCHER_ANY] = "any", [BF_MATCHER_ALL] = "all",
    1454                 :             :     [BF_MATCHER_IN] = "in",   [BF_MATCHER_RANGE] = "range",
    1455                 :             : };
    1456                 :             : 
    1457                 :             : static_assert(ARRAY_SIZE(_bf_matcher_ops_strs) == _BF_MATCHER_OP_MAX);
    1458                 :             : 
    1459                 :         425 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
    1460                 :             : {
    1461                 :             :     bf_assert(0 <= op && op < _BF_MATCHER_OP_MAX);
    1462                 :             : 
    1463                 :         425 :     return _bf_matcher_ops_strs[op];
    1464                 :             : }
    1465                 :             : 
    1466                 :        2257 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
    1467                 :             : {
    1468                 :             :     bf_assert(str);
    1469                 :             :     bf_assert(op);
    1470                 :             : 
    1471         [ +  + ]:        4845 :     for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
    1472         [ +  + ]:        4842 :         if (bf_streq(_bf_matcher_ops_strs[i], str)) {
    1473                 :        2254 :             *op = i;
    1474                 :        2254 :             return 0;
    1475                 :             :         }
    1476                 :             :     }
    1477                 :             : 
    1478                 :             :     return -EINVAL;
    1479                 :             : }
    1480                 :             : 
    1481                 :             : static const char *_bf_tcp_flags_strs[] = {
    1482                 :             :     [BF_TCP_FIN] = "fin", [BF_TCP_SYN] = "syn", [BF_TCP_RST] = "rst",
    1483                 :             :     [BF_TCP_PSH] = "psh", [BF_TCP_ACK] = "ack", [BF_TCP_URG] = "urg",
    1484                 :             :     [BF_TCP_ECE] = "ece", [BF_TCP_CWR] = "cwr",
    1485                 :             : };
    1486                 :             : static_assert(ARRAY_SIZE(_bf_tcp_flags_strs) == _BF_TCP_MAX);
    1487                 :             : 
    1488                 :          10 : const char *bf_tcp_flag_to_str(enum bf_tcp_flag flag)
    1489                 :             : {
    1490                 :             :     bf_assert(0 <= flag && flag < _BF_TCP_MAX);
    1491                 :             : 
    1492                 :          10 :     return _bf_tcp_flags_strs[flag];
    1493                 :             : }
    1494                 :             : 
    1495                 :         316 : int bf_tcp_flag_from_str(const char *str, enum bf_tcp_flag *flag)
    1496                 :             : {
    1497                 :             :     bf_assert(str);
    1498                 :             :     bf_assert(flag);
    1499                 :             : 
    1500         [ +  + ]:        1426 :     for (size_t i = 0; i < _BF_TCP_MAX; ++i) {
    1501         [ +  + ]:        1415 :         if (bf_streq_i(_bf_tcp_flags_strs[i], str)) {
    1502                 :         305 :             *flag = i;
    1503                 :         305 :             return 0;
    1504                 :             :         }
    1505                 :             :     }
    1506                 :             : 
    1507                 :             :     return -EINVAL;
    1508                 :             : }
    1509                 :             : 
    1510                 :           4 : const char *bf_ethertype_to_str(uint16_t ethertype)
    1511                 :             : {
    1512      [ +  +  + ]:           4 :     switch (ethertype) {
    1513                 :             :     case ETH_P_IP:
    1514                 :             :         return "ipv4";
    1515                 :           1 :     case ETH_P_IPV6:
    1516                 :           1 :         return "ipv6";
    1517                 :           1 :     default:
    1518                 :           1 :         return NULL;
    1519                 :             :     }
    1520                 :             : }
    1521                 :             : 
    1522                 :          82 : int bf_ethertype_from_str(const char *str, uint16_t *ethertype)
    1523                 :             : {
    1524                 :             :     bf_assert(str && ethertype);
    1525                 :             : 
    1526         [ +  + ]:          82 :     if (bf_streq_i(str, "ipv4")) {
    1527                 :          24 :         *ethertype = ETH_P_IP;
    1528                 :          24 :         return 0;
    1529                 :             :     }
    1530                 :             : 
    1531         [ +  + ]:          58 :     if (bf_streq_i(str, "ipv6")) {
    1532                 :          23 :         *ethertype = ETH_P_IPV6;
    1533                 :          23 :         return 0;
    1534                 :             :     }
    1535                 :             : 
    1536                 :             :     return -EINVAL;
    1537                 :             : }
    1538                 :             : 
    1539                 :             : static const char *_bf_ipproto_strs[UINT8_MAX + 1] = {
    1540                 :             :     [IPPROTO_HOPOPTS] = "hop",   [IPPROTO_ICMP] = "icmp",
    1541                 :             :     [IPPROTO_IGMP] = "igmp",     [IPPROTO_TCP] = "tcp",
    1542                 :             :     [IPPROTO_UDP] = "udp",       [IPPROTO_ROUTING] = "routing",
    1543                 :             :     [IPPROTO_FRAGMENT] = "frag", [IPPROTO_AH] = "ah",
    1544                 :             :     [IPPROTO_DSTOPTS] = "dst",   [IPPROTO_ICMPV6] = "icmpv6",
    1545                 :             :     [IPPROTO_MH] = "mh",
    1546                 :             : };
    1547                 :             : static_assert(ARRAY_SIZE(_bf_ipproto_strs) == (UINT8_MAX + 1),
    1548                 :             :               "missing entries in IP protocols strings array");
    1549                 :             : 
    1550                 :          10 : const char *bf_ipproto_to_str(uint8_t ipproto)
    1551                 :             : {
    1552                 :          10 :     return _bf_ipproto_strs[ipproto];
    1553                 :             : }
    1554                 :             : 
    1555                 :         291 : int bf_ipproto_from_str(const char *str, uint8_t *ipproto)
    1556                 :             : {
    1557                 :             :     bf_assert(str && ipproto);
    1558                 :             : 
    1559         [ +  + ]:       27936 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1560         [ +  + ]:       27841 :         if (bf_streq_i(str, _bf_ipproto_strs[i])) {
    1561                 :         196 :             *ipproto = (uint8_t)i;
    1562                 :         196 :             return 0;
    1563                 :             :         }
    1564                 :             :     }
    1565                 :             : 
    1566                 :             :     return -EINVAL;
    1567                 :             : }
    1568                 :             : 
    1569                 :             : #define ICMP_ROUTERADVERT 9
    1570                 :             : #define ICMP_ROUTERSOLICIT 10
    1571                 :             : 
    1572                 :             : static const char *_bf_icmp_type_strs[UINT8_MAX + 1] = {
    1573                 :             :     [ICMP_ECHOREPLY] = "echo-reply",
    1574                 :             :     [ICMP_DEST_UNREACH] = "destination-unreachable",
    1575                 :             :     [ICMP_SOURCE_QUENCH] = "source-quench",
    1576                 :             :     [ICMP_REDIRECT] = "redirect",
    1577                 :             :     [ICMP_ECHO] = "echo-request",
    1578                 :             :     [ICMP_ROUTERADVERT] = "router-advertisement",
    1579                 :             :     [ICMP_ROUTERSOLICIT] = "router-solicitation",
    1580                 :             :     [ICMP_TIME_EXCEEDED] = "time-exceeded",
    1581                 :             :     [ICMP_PARAMETERPROB] = "parameter-problem",
    1582                 :             :     [ICMP_TIMESTAMP] = "timestamp-request",
    1583                 :             :     [ICMP_TIMESTAMPREPLY] = "timestamp-reply",
    1584                 :             :     [ICMP_INFO_REQUEST] = "info-request",
    1585                 :             :     [ICMP_INFO_REPLY] = "info-reply",
    1586                 :             :     [ICMP_ADDRESS] = "address-mask-request",
    1587                 :             :     [ICMP_ADDRESSREPLY] = "address-mask-reply",
    1588                 :             : };
    1589                 :             : static_assert(ARRAY_SIZE(_bf_icmp_type_strs) == (UINT8_MAX + 1),
    1590                 :             :               "missing entries in ICMP types strings array");
    1591                 :             : 
    1592                 :           6 : const char *bf_icmp_type_to_str(uint8_t type)
    1593                 :             : {
    1594                 :           6 :     return _bf_icmp_type_strs[type];
    1595                 :             : }
    1596                 :             : 
    1597                 :          89 : int bf_icmp_type_from_str(const char *str, uint8_t *type)
    1598                 :             : {
    1599                 :             :     bf_assert(str && type);
    1600                 :             : 
    1601         [ +  + ]:       14747 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1602         [ +  + ]:       14690 :         if (bf_streq_i(str, _bf_icmp_type_strs[i])) {
    1603                 :          32 :             *type = (uint8_t)i;
    1604                 :          32 :             return 0;
    1605                 :             :         }
    1606                 :             :     }
    1607                 :             : 
    1608                 :             :     return -EINVAL;
    1609                 :             : }
    1610                 :             : 
    1611                 :             : #define ICMPV6_ND_ROUTERSOLICIT 133
    1612                 :             : #define ICMPV6_ND_ROUTERADVERT 134
    1613                 :             : #define ICMPV6_ND_NEIGHSOLICIT 135
    1614                 :             : #define ICMPV6_ND_NEIGHADVERT 136
    1615                 :             : 
    1616                 :             : static const char *_bf_icmpv6_type_strs[UINT8_MAX + 1] = {
    1617                 :             :     [ICMPV6_DEST_UNREACH] = "destination-unreachable",
    1618                 :             :     [ICMPV6_PKT_TOOBIG] = "packet-too-big",
    1619                 :             :     [ICMPV6_TIME_EXCEED] = "time-exceeded",
    1620                 :             :     [ICMPV6_PARAMPROB] = "parameter-problem",
    1621                 :             :     [ICMPV6_ECHO_REQUEST] = "echo-request",
    1622                 :             :     [ICMPV6_ECHO_REPLY] = "echo-reply",
    1623                 :             :     [ICMPV6_MGM_QUERY] = "mld-listener-query",
    1624                 :             :     [ICMPV6_MGM_REPORT] = "mld-listener-report",
    1625                 :             :     [ICMPV6_MGM_REDUCTION] = "mld-listener-reduction",
    1626                 :             :     [ICMPV6_ND_ROUTERSOLICIT] = "nd-router-solicit",
    1627                 :             :     [ICMPV6_ND_ROUTERADVERT] = "nd-router-advert",
    1628                 :             :     [ICMPV6_ND_NEIGHSOLICIT] = "nd-neighbor-solicit",
    1629                 :             :     [ICMPV6_ND_NEIGHADVERT] = "nd-neighbor-advert",
    1630                 :             :     [ICMPV6_MLD2_REPORT] = "mld2-listener-report",
    1631                 :             : };
    1632                 :             : static_assert(ARRAY_SIZE(_bf_icmpv6_type_strs) == (UINT8_MAX + 1),
    1633                 :             :               "missing entries in ICMPv6 types strings array");
    1634                 :             : 
    1635                 :           4 : const char *bf_icmpv6_type_to_str(uint8_t type)
    1636                 :             : {
    1637                 :           4 :     return _bf_icmpv6_type_strs[type];
    1638                 :             : }
    1639                 :             : 
    1640                 :          97 : int bf_icmpv6_type_from_str(const char *str, uint8_t *type)
    1641                 :             : {
    1642                 :             :     bf_assert(str && type);
    1643                 :             : 
    1644         [ +  + ]:       19970 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1645         [ +  + ]:       19911 :         if (bf_streq_i(str, _bf_icmpv6_type_strs[i])) {
    1646                 :          38 :             *type = (uint8_t)i;
    1647                 :          38 :             return 0;
    1648                 :             :         }
    1649                 :             :     }
    1650                 :             : 
    1651                 :             :     return -EINVAL;
    1652                 :             : }
        

Generated by: LCOV version 2.0-1