LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 94.1 % 511 481
Test Date: 2026-11-05 13:56:16 Functions: 97.3 % 75 73
Branches: 72.1 % 433 312

             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 <assert.h>
      19                 :             : #include <ctype.h>
      20                 :             : #include <endian.h>
      21                 :             : #include <errno.h>
      22                 :             : #include <inttypes.h>
      23                 :             : #include <limits.h>
      24                 :             : #include <math.h>
      25                 :             : #include <stdint.h>
      26                 :             : #include <stdlib.h>
      27                 :             : #include <string.h>
      28                 :             : 
      29                 :             : #include "bpfilter/dump.h"
      30                 :             : #include "bpfilter/helper.h"
      31                 :             : #include "bpfilter/hook.h"
      32                 :             : #include "bpfilter/if.h"
      33                 :             : #include "bpfilter/logger.h"
      34                 :             : #include "bpfilter/pack.h"
      35                 :             : #include "bpfilter/runtime.h"
      36                 :             : #include "bpfilter/set.h"
      37                 :             : 
      38                 :             : #define INET4_ADDRSTRLEN 16
      39                 :             : #define INET6_ADDRSTRLEN 46
      40                 :             : #define BF_DSCP_MAX 63
      41                 :             : 
      42                 :             : #define BF_PAYLOAD_OPS(type, size, parser_cb, printer_cb)                      \
      43                 :             :     [type] = {size, parser_cb, printer_cb}
      44                 :             : 
      45                 :             : extern int inet_pton(int, const char *, void *);
      46                 :             : extern const char *inet_ntop(int, const void *, char *, socklen_t);
      47                 :             : 
      48                 :             : /**
      49                 :             :  * Matcher definition.
      50                 :             :  *
      51                 :             :  * Matchers are criterias to match the packet against. A set of matcher defines
      52                 :             :  * what a rule should match on.
      53                 :             :  *
      54                 :             :  * @todo `bf_matcher`'s payload should be a union of all the possible payload
      55                 :             :  * types.
      56                 :             :  */
      57                 :             : struct bf_matcher
      58                 :             : {
      59                 :             :     /// Matcher type.
      60                 :             :     enum bf_matcher_type type;
      61                 :             :     /// Comparison operator.
      62                 :             :     enum bf_matcher_op op;
      63                 :             :     /// Negate the comparison result.
      64                 :             :     bool negate;
      65                 :             :     /// Total matcher size (including payload).
      66                 :             :     size_t len;
      67                 :             :     /// Payload to match the packet against (if any).
      68                 :             :     uint8_t payload[];
      69                 :             : };
      70                 :             : 
      71                 :             : /**
      72                 :             :  * @brief Parse a string into an unsigned long.
      73                 :             :  *
      74                 :             :  * Tries base-10 first. If that fails to consume the full string, retries
      75                 :             :  * as base-16 (accepts "0x" prefix). Returns -EINVAL if neither succeeds.
      76                 :             :  *
      77                 :             :  * @param str String to parse. Must not be NULL.
      78                 :             :  * @param value Parsed value. Must not be NULL.
      79                 :             :  * @return 0 on success, negative errno on failure.
      80                 :             :  */
      81                 :         578 : static int _bf_strtoul(const char *str, unsigned long *value)
      82                 :             : {
      83                 :             :     char *endptr;
      84                 :             : 
      85                 :             :     assert(str);
      86                 :             :     assert(value);
      87                 :             : 
      88         [ +  - ]:         578 :     if (*str == '\0')
      89                 :             :         return -EINVAL;
      90                 :             : 
      91                 :         578 :     errno = 0;
      92                 :         578 :     *value = strtoul(str, &endptr, BF_BASE_10);
      93   [ +  +  -  + ]:         578 :     if (*endptr != '\0' || errno == ERANGE) {
      94                 :         253 :         errno = 0;
      95                 :         253 :         *value = strtoul(str, &endptr, BF_BASE_16);
      96   [ +  +  -  + ]:         253 :         if (*endptr != '\0' || errno == ERANGE)
      97                 :          47 :             return -EINVAL;
      98                 :             :     }
      99                 :             : 
     100                 :             :     return 0;
     101                 :             : }
     102                 :             : 
     103                 :          46 : static int _bf_parse_u32(enum bf_matcher_type type, enum bf_matcher_op op,
     104                 :             :                          void *payload, const char *raw_payload)
     105                 :             : {
     106                 :             :     unsigned long value;
     107                 :             : 
     108                 :             :     assert(payload);
     109                 :             :     assert(raw_payload);
     110                 :             : 
     111   [ +  +  +  + ]:          46 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT32_MAX) {
     112                 :          36 :         *(uint32_t *)payload = (uint32_t)value;
     113                 :          36 :         return 0;
     114                 :             :     }
     115                 :             : 
     116         [ +  - ]:          10 :     return bf_err_r(
     117                 :             :         -EINVAL,
     118                 :             :         "\"%s %s\" expects a valid 32-bit value in decimal or hexadecimal notation, not '%s'",
     119                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     120                 :             : }
     121                 :             : 
     122                 :           0 : static void _bf_print_u32(const void *payload)
     123                 :             : {
     124                 :             :     assert(payload);
     125                 :             : 
     126                 :           0 :     (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
     127                 :           0 : }
     128                 :             : 
     129                 :             : #define BF_U32_RANGE_MAX_LEN 32 /* 4294967295-4294967295 */
     130                 :             : 
     131                 :          24 : static int _bf_parse_u32_range(enum bf_matcher_type type, enum bf_matcher_op op,
     132                 :             :                                void *payload, const char *raw_payload)
     133                 :             : {
     134                 :             :     uint32_t *range;
     135                 :             :     char buf[BF_U32_RANGE_MAX_LEN];
     136                 :             :     char *first;
     137                 :             :     char *second;
     138                 :             :     unsigned long value;
     139                 :             : 
     140                 :             :     assert(payload);
     141                 :             :     assert(raw_payload);
     142                 :             : 
     143                 :             :     range = (uint32_t *)payload;
     144                 :             : 
     145                 :          24 :     bf_strncpy(buf, BF_U32_RANGE_MAX_LEN, raw_payload);
     146                 :             : 
     147         [ -  + ]:          24 :     if (!isdigit(*raw_payload))
     148                 :           0 :         goto err;
     149                 :             : 
     150                 :          24 :     first = strtok_r(buf, "-", &second);
     151         [ -  + ]:          24 :     if (!first)
     152                 :           0 :         goto err;
     153                 :             : 
     154         [ +  + ]:          24 :     if (!*second)
     155                 :           1 :         goto err;
     156                 :             : 
     157   [ +  +  -  + ]:          23 :     if (_bf_strtoul(first, &value) || value > UINT32_MAX)
     158                 :           1 :         goto err;
     159                 :          22 :     range[0] = (uint32_t)value;
     160                 :             : 
     161   [ +  -  -  + ]:          22 :     if (_bf_strtoul(second, &value) || value > UINT32_MAX)
     162                 :           0 :         goto err;
     163                 :          22 :     range[1] = (uint32_t)value;
     164                 :             : 
     165         [ +  + ]:          22 :     if (range[1] < range[0])
     166                 :           2 :         goto err;
     167                 :             : 
     168                 :             :     return 0;
     169                 :             : 
     170                 :           4 : err:
     171         [ +  - ]:           4 :     bf_err(
     172                 :             :         "\"%s %s\" expects two positive decimal and hexadecimal integers as `$START-$END`, with `$START <= $END`, not '%s'",
     173                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     174                 :             : 
     175                 :             :     return -EINVAL;
     176                 :             : }
     177                 :             : 
     178                 :           0 : static void _bf_print_u32_range(const void *payload)
     179                 :             : {
     180                 :             :     assert(payload);
     181                 :             : 
     182                 :             :     uint32_t *range = (uint32_t *)payload;
     183                 :             : 
     184                 :           0 :     (void)fprintf(stdout, "0x%" PRIx32 "-0x%" PRIx32, range[0], range[1]);
     185                 :           0 : }
     186                 :             : 
     187                 :          42 : static int _bf_parse_iface(enum bf_matcher_type type, enum bf_matcher_op op,
     188                 :             :                            void *payload, const char *raw_payload)
     189                 :             : {
     190                 :             :     assert(payload);
     191                 :             :     assert(raw_payload);
     192                 :             : 
     193                 :             :     int r;
     194                 :             : 
     195                 :          42 :     r = bf_if_index_from_str(raw_payload, (uint32_t *)payload);
     196         [ +  + ]:          42 :     if (r) {
     197         [ +  - ]:          11 :         return bf_err_r(
     198                 :             :             r,
     199                 :             :             "\"%s %s\" expects an interface name (e.g., \"eth0\", \"wlan0\") or a decimal interface index (e.g., \"1\", \"2\"), not '%s'",
     200                 :             :             bf_matcher_type_to_str(type), bf_matcher_op_to_str(op),
     201                 :             :             raw_payload);
     202                 :             :     }
     203                 :             : 
     204                 :             :     return 0;
     205                 :             : }
     206                 :             : 
     207                 :           2 : static void _bf_print_iface(const void *payload)
     208                 :             : {
     209                 :             :     assert(payload);
     210                 :             : 
     211                 :             :     const char *ifname;
     212                 :           2 :     uint32_t ifindex = *(uint32_t *)payload;
     213                 :             : 
     214                 :           2 :     ifname = bf_if_name_from_index((int)ifindex);
     215         [ +  + ]:           2 :     if (ifname)
     216                 :           1 :         (void)fprintf(stdout, "%s", ifname);
     217                 :             :     else
     218                 :           1 :         (void)fprintf(stdout, "%" PRIu32, ifindex);
     219                 :           2 : }
     220                 :             : 
     221                 :          90 : static int _bf_parse_l3_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     222                 :             :                               void *payload, const char *raw_payload)
     223                 :             : {
     224                 :             :     unsigned long value;
     225                 :             : 
     226                 :             :     assert(payload);
     227                 :             :     assert(raw_payload);
     228                 :             : 
     229         [ +  + ]:          90 :     if (!bf_ethertype_from_str(raw_payload, payload))
     230                 :             :         return 0;
     231                 :             : 
     232   [ +  +  +  + ]:          34 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT16_MAX) {
     233                 :          28 :         *(uint16_t *)payload = (uint16_t)value;
     234                 :          28 :         return 0;
     235                 :             :     }
     236                 :             : 
     237         [ +  - ]:           6 :     return bf_err_r(
     238                 :             :         -EINVAL,
     239                 :             :         "\"%s %s\" expects an internet layer protocol name (e.g. \"IPv6\", case insensitive), or a valid decimal or hexadecimal IEEE 802 number, not '%s'",
     240                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     241                 :             : }
     242                 :             : 
     243                 :           2 : static void _bf_print_l3_proto(const void *payload)
     244                 :             : {
     245                 :             :     assert(payload);
     246                 :             : 
     247                 :           2 :     const char *ethertype = bf_ethertype_to_str(*(uint16_t *)payload);
     248                 :             : 
     249         [ +  + ]:           2 :     if (ethertype)
     250                 :           1 :         (void)fprintf(stdout, "%s", ethertype);
     251                 :             :     else
     252                 :           1 :         (void)fprintf(stdout, "0x%04" PRIx16, *(uint16_t *)payload);
     253                 :           2 : }
     254                 :             : 
     255                 :         390 : static int _bf_parse_l4_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     256                 :             :                               void *payload, const char *raw_payload)
     257                 :             : {
     258                 :             :     unsigned long value;
     259                 :             : 
     260                 :             :     assert(payload);
     261                 :             :     assert(raw_payload);
     262                 :             : 
     263         [ +  + ]:         390 :     if (!bf_ipproto_from_str(raw_payload, payload))
     264                 :             :         return 0;
     265                 :             : 
     266   [ +  +  +  + ]:         100 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT8_MAX) {
     267                 :          66 :         *(uint8_t *)payload = (uint8_t)value;
     268                 :          66 :         return 0;
     269                 :             :     }
     270                 :             : 
     271         [ +  - ]:          34 :     return bf_err_r(
     272                 :             :         -EINVAL,
     273                 :             :         "\"%s %s\" expects a transport layer protocol name (e.g. \"ICMP\", case insensitive), or a valid decimal or hexadecimal internet protocol number, not '%s'",
     274                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     275                 :             : }
     276                 :             : 
     277                 :           5 : static void _bf_print_l4_proto(const void *payload)
     278                 :             : {
     279                 :             :     assert(payload);
     280                 :             : 
     281                 :           5 :     const char *ipproto = bf_ipproto_to_str(*(uint8_t *)payload);
     282                 :             : 
     283         [ +  + ]:           5 :     if (ipproto)
     284                 :           4 :         (void)fprintf(stdout, "%s", ipproto);
     285                 :             :     else
     286                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     287                 :           5 : }
     288                 :             : 
     289                 :         760 : static int _bf_parse_l4_port(enum bf_matcher_type type, enum bf_matcher_op op,
     290                 :             :                              void *payload, const char *raw_payload)
     291                 :             : {
     292                 :             :     assert(payload);
     293                 :             :     assert(raw_payload);
     294                 :             : 
     295                 :             :     unsigned long port;
     296                 :             :     char *endptr;
     297                 :             : 
     298                 :         760 :     port = strtoul(raw_payload, &endptr, BF_BASE_10);
     299   [ +  +  +  + ]:         760 :     if (*endptr == '\0' && port <= UINT16_MAX) {
     300                 :         698 :         *(uint16_t *)payload = htobe16((uint16_t)port);
     301                 :         698 :         return 0;
     302                 :             :     }
     303                 :             : 
     304         [ +  - ]:          62 :     bf_err("\"%s %s\" expects a valid decimal port number, not '%s'",
     305                 :             :            bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     306                 :             : 
     307                 :             :     return -EINVAL;
     308                 :             : }
     309                 :             : 
     310                 :           5 : static void _bf_print_l4_port(const void *payload)
     311                 :             : {
     312                 :             :     assert(payload);
     313                 :             : 
     314                 :           5 :     (void)fprintf(stdout, "%" PRIu16, (uint16_t)be16toh(*(uint16_t *)payload));
     315                 :           5 : }
     316                 :             : 
     317                 :             : #define BF_PORT_RANGE_MAX_LEN 16 // 65535-65535, with nul char, round to **2
     318                 :             : 
     319                 :         251 : static int _bf_parse_l4_port_range(enum bf_matcher_type type,
     320                 :             :                                    enum bf_matcher_op op, void *payload,
     321                 :             :                                    const char *raw_payload)
     322                 :             : {
     323                 :             :     assert(payload);
     324                 :             :     assert(raw_payload);
     325                 :             : 
     326                 :             :     uint16_t *ports = (uint16_t *)payload;
     327                 :             :     unsigned long port;
     328                 :             :     char buf[BF_PORT_RANGE_MAX_LEN];
     329                 :             :     char *first;
     330                 :             :     char *second;
     331                 :             :     char *endptr;
     332                 :             : 
     333                 :         251 :     bf_strncpy(buf, BF_PORT_RANGE_MAX_LEN, raw_payload);
     334                 :             : 
     335         [ +  + ]:         251 :     if (!isdigit(*raw_payload))
     336                 :          26 :         goto err;
     337                 :             : 
     338                 :         225 :     first = strtok_r(buf, "-", &second);
     339         [ -  + ]:         225 :     if (!first)
     340                 :           0 :         goto err;
     341                 :             : 
     342         [ +  + ]:         225 :     if (!*second)
     343                 :          15 :         goto err;
     344                 :             : 
     345                 :         210 :     port = strtoul(first, &endptr, BF_BASE_10);
     346   [ +  +  +  + ]:         210 :     if (*endptr != '\0' || port > UINT16_MAX)
     347                 :          18 :         goto err;
     348                 :         192 :     ports[0] = (uint16_t)port;
     349                 :             : 
     350                 :         192 :     port = strtoul(second, &endptr, BF_BASE_10);
     351   [ +  -  +  + ]:         192 :     if (*endptr != '\0' || port > UINT16_MAX)
     352                 :           1 :         goto err;
     353                 :         191 :     ports[1] = (uint16_t)port;
     354                 :             : 
     355         [ +  + ]:         191 :     if (ports[1] < ports[0])
     356                 :           8 :         goto err;
     357                 :             : 
     358                 :             :     return 0;
     359                 :             : 
     360                 :          68 : err:
     361         [ +  - ]:          68 :     bf_err(
     362                 :             :         "\"%s %s\" expects two positive decimal port numbers as `$START-$END`, with `$START <= $END`, not '%s'",
     363                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     364                 :             : 
     365                 :             :     return -EINVAL;
     366                 :             : }
     367                 :             : 
     368                 :           1 : static void _bf_print_l4_port_range(const void *payload)
     369                 :             : {
     370                 :             :     assert(payload);
     371                 :             : 
     372                 :             :     uint16_t *ports = (uint16_t *)payload;
     373                 :             : 
     374                 :           1 :     (void)fprintf(stdout, "%" PRIu16 "-%" PRIu16, ports[0], ports[1]);
     375                 :           1 : }
     376                 :             : 
     377                 :          97 : static int _bf_parse_probability(enum bf_matcher_type type,
     378                 :             :                                  enum bf_matcher_op op, void *payload,
     379                 :             :                                  const char *raw_payload)
     380                 :             : {
     381                 :             :     assert(payload);
     382                 :             :     assert(raw_payload);
     383                 :             : 
     384                 :             :     double proba;
     385                 :             :     char *endptr;
     386                 :             : 
     387                 :          97 :     proba = strtod(raw_payload, &endptr);
     388   [ +  +  +  -  :          97 :     if (endptr[0] == '%' && endptr[1] == '\0' && proba >= 0.0 &&
             +  +  +  + ]
     389                 :             :         proba <= 100.0) {
     390                 :          86 :         *(float *)payload = (float)proba;
     391                 :          86 :         return 0;
     392                 :             :     }
     393                 :             : 
     394         [ +  - ]:          11 :     bf_err(
     395                 :             :         "\"%s %s\" expects a valid percentage value (i.e., within [0%%, 100%%], e.g., \"50%%\" or \"33.33%%\"), not '%s'",
     396                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     397                 :             : 
     398                 :             :     return -EINVAL;
     399                 :             : }
     400                 :             : 
     401                 :           4 : static void _bf_print_probability(const void *payload)
     402                 :             : {
     403                 :             :     assert(payload);
     404                 :             : 
     405                 :           4 :     float proba = *(float *)payload;
     406         [ +  + ]:           4 :     if (proba == floorf(proba))
     407                 :           2 :         (void)fprintf(stdout, "%.0f%%", proba);
     408                 :             :     else
     409                 :           2 :         (void)fprintf(stdout, "%g%%", proba);
     410                 :           4 : }
     411                 :             : 
     412                 :          38 : static int _bf_parse_mark(enum bf_matcher_type type, enum bf_matcher_op op,
     413                 :             :                           void *payload, const char *raw_payload)
     414                 :             : {
     415                 :             :     long long mark;
     416                 :             :     char *endptr;
     417                 :             : 
     418                 :             :     assert(payload);
     419                 :             :     assert(raw_payload);
     420                 :             : 
     421                 :             :     (void)type;
     422                 :             :     (void)op;
     423                 :             : 
     424                 :          38 :     mark = strtoll(raw_payload, &endptr, 0);
     425         [ +  + ]:          38 :     if (*endptr) {
     426         [ +  - ]:           3 :         return bf_err_r(-EINVAL,
     427                 :             :                         "mark value '%s' can't be parsed as a positive integer",
     428                 :             :                         raw_payload);
     429                 :             :     }
     430         [ +  + ]:          35 :     if (mark < 0) {
     431         [ +  - ]:           2 :         return bf_err_r(-EINVAL, "mark should be positive, not '%s'",
     432                 :             :                         raw_payload);
     433                 :             :     }
     434         [ +  + ]:          33 :     if (mark > UINT32_MAX)
     435         [ +  - ]:           2 :         return bf_err_r(-EINVAL, "mark should be at most 0x%x", UINT32_MAX);
     436                 :             : 
     437                 :          31 :     *(uint32_t *)payload = (uint32_t)mark;
     438                 :             : 
     439                 :          31 :     return 0;
     440                 :             : }
     441                 :             : 
     442                 :           1 : static void _bf_print_mark(const void *payload)
     443                 :             : {
     444                 :             :     assert(payload);
     445                 :             : 
     446                 :           1 :     (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
     447                 :           1 : }
     448                 :             : 
     449                 :          74 : static int _bf_parse_pid(enum bf_matcher_type type, enum bf_matcher_op op,
     450                 :             :                          void *payload, const char *raw_payload)
     451                 :             : {
     452                 :             :     unsigned long pid;
     453                 :             :     char *endptr;
     454                 :             : 
     455                 :             :     assert(payload);
     456                 :             :     assert(raw_payload);
     457                 :             : 
     458                 :             :     /* The kernel never assigns PID 0 to a process, and PIDs are stored in a
     459                 :             :      * signed `pid_t`: accept [1, INT32_MAX] only. */
     460                 :          74 :     errno = 0;
     461                 :          74 :     pid = strtoul(raw_payload, &endptr, BF_BASE_10);
     462   [ +  +  +  +  :          74 :     if (isdigit(*raw_payload) && *endptr == '\0' && errno != ERANGE &&
                   +  + ]
     463         [ +  + ]:          61 :         pid != 0 && pid <= INT32_MAX) {
     464                 :             :         /* Set elements pack their components: `payload` might be misaligned
     465                 :             :          * for a direct 4-byte store. */
     466                 :          56 :         uint32_t value = (uint32_t)pid;
     467                 :             : 
     468                 :          56 :         memcpy(payload, &value, sizeof(value));
     469                 :             : 
     470                 :             :         return 0;
     471                 :             :     }
     472                 :             : 
     473         [ +  - ]:          18 :     return bf_err_r(
     474                 :             :         -EINVAL,
     475                 :             :         "\"%s %s\" expects a decimal process ID between 1 and %d, not '%s'",
     476                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), INT32_MAX,
     477                 :             :         raw_payload);
     478                 :             : }
     479                 :             : 
     480                 :           1 : static void _bf_print_pid(const void *payload)
     481                 :             : {
     482                 :             :     assert(payload);
     483                 :             : 
     484                 :           1 :     (void)fprintf(stdout, "%" PRIu32, *(uint32_t *)payload);
     485                 :           1 : }
     486                 :             : 
     487                 :         320 : static int _bf_parse_ipv4_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     488                 :             :                                void *payload, const char *raw_payload)
     489                 :             : {
     490                 :             :     assert(payload);
     491                 :             :     assert(raw_payload);
     492                 :             : 
     493                 :             :     int r;
     494                 :             : 
     495                 :         320 :     r = inet_pton(AF_INET, raw_payload, payload);
     496         [ +  + ]:         320 :     if (r == 1)
     497                 :             :         return 0;
     498                 :             : 
     499         [ +  - ]:           7 :     bf_err(
     500                 :             :         "\"%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' ",
     501                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     502                 :             : 
     503                 :             :     return -EINVAL;
     504                 :             : }
     505                 :             : 
     506                 :          41 : static void _bf_print_ipv4_addr(const void *payload)
     507                 :             : {
     508                 :             :     assert(payload);
     509                 :             : 
     510                 :             :     char str[INET4_ADDRSTRLEN];
     511                 :             : 
     512         [ +  - ]:          41 :     if (inet_ntop(AF_INET, payload, str, INET4_ADDRSTRLEN))
     513                 :          41 :         (void)fprintf(stdout, "%s", str);
     514                 :             :     else
     515                 :           0 :         (void)fprintf(stdout, "<failed to print IPv4 address>");
     516                 :          41 : }
     517                 :             : 
     518                 :             : #define BF_IPV4_NET_MAX_LEN                                                    \
     519                 :             :     32 // 255.255.255.255/32, with nul char, round to **2
     520                 :             : 
     521                 :         116 : static int _bf_parse_ipv4_net(enum bf_matcher_type type, enum bf_matcher_op op,
     522                 :             :                               void *payload, const char *raw_payload)
     523                 :             : {
     524                 :             :     assert(payload);
     525                 :             :     assert(raw_payload);
     526                 :             : 
     527                 :             :     struct bf_ip4_lpm_key *addr = payload;
     528                 :             :     char buf[BF_IPV4_NET_MAX_LEN];
     529                 :             :     char *strip, *strmask, *endptr;
     530                 :             :     int r;
     531                 :             : 
     532                 :         116 :     bf_strncpy(buf, BF_IPV4_NET_MAX_LEN, raw_payload);
     533                 :             : 
     534         [ +  + ]:         116 :     if (!isdigit(*raw_payload))
     535                 :           4 :         goto err;
     536                 :             : 
     537                 :         112 :     strip = strtok_r(buf, "/", &strmask);
     538   [ +  -  +  + ]:         112 :     if (!strip || !*strmask)
     539                 :           1 :         goto err;
     540                 :             : 
     541                 :         111 :     r = inet_pton(AF_INET, strip, &addr->data);
     542         [ +  + ]:         111 :     if (r != 1)
     543                 :           1 :         goto err;
     544                 :             : 
     545                 :         110 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     546   [ +  +  +  + ]:         110 :     if (*endptr != '\0' || addr->prefixlen > 32)
     547                 :          13 :         goto err;
     548                 :             : 
     549                 :             :     return 0;
     550                 :             : 
     551                 :          19 : err:
     552         [ +  - ]:          19 :     bf_err(
     553                 :             :         "\"%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' ",
     554                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     555                 :             : 
     556                 :             :     return -EINVAL;
     557                 :             : }
     558                 :             : 
     559                 :           1 : static void _bf_print_ipv4_net(const void *payload)
     560                 :             : {
     561                 :             :     assert(payload);
     562                 :             : 
     563                 :             :     char str[INET4_ADDRSTRLEN];
     564                 :             :     const struct bf_ip4_lpm_key *addr = payload;
     565                 :             : 
     566         [ +  - ]:           1 :     if (inet_ntop(AF_INET, &addr->data, str, INET4_ADDRSTRLEN))
     567                 :           1 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     568                 :             :     else
     569                 :           0 :         (void)fprintf(stdout, "<failed to print IPv4 network>");
     570                 :           1 : }
     571                 :             : 
     572                 :         224 : static int _bf_parse_ipv6_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     573                 :             :                                void *payload, const char *raw_payload)
     574                 :             : {
     575                 :             :     assert(payload);
     576                 :             :     assert(raw_payload);
     577                 :             : 
     578                 :             :     int r;
     579                 :             : 
     580                 :         224 :     r = inet_pton(AF_INET6, raw_payload, payload);
     581         [ +  + ]:         224 :     if (r == 1)
     582                 :             :         return 0;
     583                 :             : 
     584         [ +  - ]:          36 :     bf_err(
     585                 :             :         "\"%s %s\" expects an IPv6 address composed of 8 hexadecimal numbers (abbreviations are supported), 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 : static void _bf_print_ipv6_addr(const void *payload)
     592                 :             : {
     593                 :             :     assert(payload);
     594                 :             : 
     595                 :             :     char str[INET6_ADDRSTRLEN];
     596                 :             : 
     597         [ +  - ]:           1 :     if (inet_ntop(AF_INET6, payload, str, INET6_ADDRSTRLEN))
     598                 :           1 :         (void)fprintf(stdout, "%s", str);
     599                 :             :     else
     600                 :           0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     601                 :           1 : }
     602                 :             : 
     603                 :             : #define BF_IPV6_NET_MAX_LEN (INET6_ADDRSTRLEN + 4)
     604                 :             : 
     605                 :         306 : static int _bf_parse_ipv6_net(enum bf_matcher_type type, enum bf_matcher_op op,
     606                 :             :                               void *payload, const char *raw_payload)
     607                 :             : {
     608                 :             :     assert(payload);
     609                 :             :     assert(raw_payload);
     610                 :             : 
     611                 :             :     struct bf_ip6_lpm_key *addr = payload;
     612                 :             :     char buf[BF_IPV6_NET_MAX_LEN];
     613                 :             :     char *strip, *strmask, *endptr;
     614                 :             :     int r;
     615                 :             : 
     616                 :         306 :     bf_strncpy(buf, BF_IPV6_NET_MAX_LEN, raw_payload);
     617                 :             : 
     618   [ +  +  +  +  :         306 :     if (!isalpha(*raw_payload) && !isdigit(*raw_payload) && *raw_payload != ':')
                   +  + ]
     619                 :          12 :         goto err;
     620                 :             : 
     621                 :         294 :     strip = strtok_r(buf, "/", &strmask);
     622   [ +  -  +  + ]:         294 :     if (!strip || !*strmask)
     623                 :          29 :         goto err;
     624                 :             : 
     625                 :         265 :     r = inet_pton(AF_INET6, strip, &addr->data);
     626         [ +  + ]:         265 :     if (r != 1)
     627                 :          13 :         goto err;
     628                 :             : 
     629                 :         252 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     630   [ +  +  +  + ]:         252 :     if (*endptr != '\0' || addr->prefixlen > 128)
     631                 :          33 :         goto err;
     632                 :             : 
     633                 :             :     return 0;
     634                 :             : 
     635                 :          87 : err:
     636         [ +  - ]:          87 :     bf_err(
     637                 :             :         "\"%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' ",
     638                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     639                 :             : 
     640                 :             :     return -EINVAL;
     641                 :             : }
     642                 :             : 
     643                 :           1 : static void _bf_print_ipv6_net(const void *payload)
     644                 :             : {
     645                 :             :     assert(payload);
     646                 :             : 
     647                 :             :     const struct bf_ip6_lpm_key *addr = payload;
     648                 :             :     char str[INET6_ADDRSTRLEN];
     649                 :             : 
     650         [ +  - ]:           1 :     if (inet_ntop(AF_INET6, addr->data, str, INET6_ADDRSTRLEN))
     651                 :           1 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     652                 :             :     else
     653                 :           0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     654                 :           1 : }
     655                 :             : 
     656                 :         147 : static int _bf_parse_tcp_flags(enum bf_matcher_type type, enum bf_matcher_op op,
     657                 :             :                                void *payload, const char *raw_payload)
     658                 :             : {
     659                 :             :     assert(payload);
     660                 :             :     assert(raw_payload);
     661                 :             : 
     662                 :             :     _cleanup_free_ char *_raw_payload = NULL;
     663                 :             :     char *tmp;
     664                 :             :     char *saveptr;
     665                 :             :     char *token;
     666                 :             :     uint8_t *flags = payload;
     667                 :             : 
     668                 :         147 :     _raw_payload = strdup(raw_payload);
     669         [ -  + ]:         147 :     if (!_raw_payload)
     670                 :           0 :         goto err;
     671                 :             : 
     672                 :         147 :     *flags = 0;
     673                 :             :     tmp = _raw_payload;
     674                 :             : 
     675         [ +  + ]:         454 :     while ((token = strtok_r(tmp, ",", &saveptr))) {
     676                 :             :         enum bf_tcp_flag new_flag;
     677                 :             :         int r;
     678                 :             : 
     679                 :         316 :         r = bf_tcp_flag_from_str(token, &new_flag);
     680         [ +  + ]:         316 :         if (r)
     681                 :           9 :             goto err;
     682                 :             : 
     683                 :         307 :         *flags |= (uint8_t)(1 << new_flag);
     684                 :             : 
     685                 :             :         tmp = NULL;
     686                 :             :     }
     687                 :             : 
     688                 :             :     return 0;
     689                 :             : 
     690                 :           9 : err:
     691         [ +  - ]:           9 :     bf_err(
     692                 :             :         "\"%s %s\" expects a comma-separated list of one or more TCP flags (fin, syn, rst, psh, ack, urg, ece, or cwr), not '%s' ",
     693                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     694                 :             : 
     695                 :             :     return -EINVAL;
     696                 :             : }
     697                 :             : 
     698                 :           1 : static void _bf_print_tcp_flags(const void *payload)
     699                 :             : {
     700                 :             :     assert(payload);
     701                 :             : 
     702                 :           1 :     uint8_t flag = *(uint8_t *)payload;
     703                 :             : 
     704         [ +  + ]:           9 :     for (uint32_t i = 0; i < _BF_TCP_MAX; ++i) {
     705         [ +  + ]:           8 :         if (flag & (1 << i)) {
     706                 :           2 :             flag &= ~(1 << i);
     707         [ +  + ]:           3 :             (void)fprintf(stdout, "%s%s", bf_tcp_flag_to_str(i),
     708                 :             :                           flag ? "," : "");
     709                 :             :         }
     710                 :             :     }
     711                 :           1 : }
     712                 :             : 
     713                 :          88 : static int _bf_parse_icmp_type(enum bf_matcher_type type, enum bf_matcher_op op,
     714                 :             :                                void *payload, const char *raw_payload)
     715                 :             : {
     716                 :             :     unsigned long value;
     717                 :             : 
     718                 :             :     assert(payload);
     719                 :             :     assert(raw_payload);
     720                 :             : 
     721         [ +  + ]:          88 :     if (!bf_icmp_type_from_str(raw_payload, payload))
     722                 :             :         return 0;
     723                 :             : 
     724   [ +  +  +  + ]:          56 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT8_MAX) {
     725                 :          44 :         *(uint8_t *)payload = (uint8_t)value;
     726                 :          44 :         return 0;
     727                 :             :     }
     728                 :             : 
     729         [ +  - ]:          12 :     return bf_err_r(
     730                 :             :         -EINVAL,
     731                 :             :         "\"%s %s\" expects an ICMP type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMP type value, not '%s'",
     732                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     733                 :             : }
     734                 :             : 
     735                 :           2 : static void _bf_print_icmp_type(const void *payload)
     736                 :             : {
     737                 :             :     assert(payload);
     738                 :             : 
     739                 :           2 :     const char *type = bf_icmp_type_to_str(*(uint8_t *)payload);
     740                 :             : 
     741         [ +  + ]:           2 :     if (type)
     742                 :           1 :         (void)fprintf(stdout, "%s", type);
     743                 :             :     else
     744                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     745                 :           2 : }
     746                 :             : 
     747                 :         166 : static int _bf_parse_icmp_code(enum bf_matcher_type type, enum bf_matcher_op op,
     748                 :             :                                void *payload, const char *raw_payload)
     749                 :             : {
     750                 :             :     unsigned long value;
     751                 :             : 
     752                 :             :     assert(payload);
     753                 :             :     assert(raw_payload);
     754                 :             : 
     755   [ +  +  +  + ]:         166 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT8_MAX) {
     756                 :         142 :         *(uint8_t *)payload = (uint8_t)value;
     757                 :         142 :         return 0;
     758                 :             :     }
     759                 :             : 
     760         [ +  - ]:          24 :     return bf_err_r(
     761                 :             :         -EINVAL,
     762                 :             :         "\"%s %s\" expects a decimal or hexadecimal ICMP or ICMPv6 code value, not '%s'",
     763                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     764                 :             : }
     765                 :             : 
     766                 :           1 : static void _bf_print_icmp_code(const void *payload)
     767                 :             : {
     768                 :             :     assert(payload);
     769                 :             : 
     770                 :           1 :     (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     771                 :           1 : }
     772                 :             : 
     773                 :          87 : static int _bf_parse_dscp(enum bf_matcher_type type, enum bf_matcher_op op,
     774                 :             :                           void *payload, const char *raw_payload)
     775                 :             : {
     776                 :             :     unsigned long value;
     777                 :             : 
     778                 :             :     assert(payload);
     779                 :             :     assert(raw_payload);
     780                 :             : 
     781         [ +  + ]:          87 :     if (!bf_dscp_class_from_str(raw_payload, payload))
     782                 :             :         return 0;
     783                 :             : 
     784   [ +  +  +  + ]:          73 :     if (!_bf_strtoul(raw_payload, &value) && value <= BF_DSCP_MAX) {
     785                 :          39 :         *(uint8_t *)payload = (uint8_t)value;
     786                 :          39 :         return 0;
     787                 :             :     }
     788                 :             : 
     789         [ +  - ]:          34 :     return bf_err_r(
     790                 :             :         -EINVAL,
     791                 :             :         "\"%s %s\" expects a DSCP value (0-63, decimal/hex) or class name, not '%s'",
     792                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     793                 :             : }
     794                 :             : 
     795                 :           1 : static void _bf_print_dscp(const void *payload)
     796                 :             : {
     797                 :             :     const char *name;
     798                 :             : 
     799                 :             :     assert(payload);
     800                 :             : 
     801                 :           1 :     name = bf_dscp_class_to_str(*(uint8_t *)payload);
     802                 :             : 
     803         [ +  - ]:           1 :     if (name)
     804                 :           1 :         (void)fprintf(stdout, "%s", name);
     805                 :             :     else
     806                 :           0 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     807                 :           1 : }
     808                 :             : 
     809                 :          96 : static int _bf_parse_icmpv6_type(enum bf_matcher_type type,
     810                 :             :                                  enum bf_matcher_op op, void *payload,
     811                 :             :                                  const char *raw_payload)
     812                 :             : {
     813                 :             :     unsigned long value;
     814                 :             : 
     815                 :             :     assert(payload);
     816                 :             :     assert(raw_payload);
     817                 :             : 
     818         [ +  + ]:          96 :     if (!bf_icmpv6_type_from_str(raw_payload, payload))
     819                 :             :         return 0;
     820                 :             : 
     821   [ +  +  +  + ]:          58 :     if (!_bf_strtoul(raw_payload, &value) && value <= UINT8_MAX) {
     822                 :          46 :         *(uint8_t *)payload = (uint8_t)value;
     823                 :          46 :         return 0;
     824                 :             :     }
     825                 :             : 
     826         [ +  - ]:          12 :     return bf_err_r(
     827                 :             :         -EINVAL,
     828                 :             :         "\"%s %s\" expects an ICMPv6 type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMPv6 type value, not '%s'",
     829                 :             :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     830                 :             : }
     831                 :             : 
     832                 :           2 : static void _bf_print_icmpv6_type(const void *payload)
     833                 :             : {
     834                 :             :     assert(payload);
     835                 :             : 
     836                 :           2 :     const char *type = bf_icmpv6_type_to_str(*(uint8_t *)payload);
     837                 :             : 
     838         [ +  + ]:           2 :     if (type)
     839                 :           1 :         (void)fprintf(stdout, "%s", type);
     840                 :             :     else
     841                 :           1 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     842                 :           2 : }
     843                 :             : 
     844                 :             : #define BF_MATCHER_OPS(op, payload_size, parse_cb, print_cb)                   \
     845                 :             :     [op] = {payload_size, parse_cb, print_cb}
     846                 :             : 
     847                 :             : #define _BF_TCP_FLAGS_OFFSET 13
     848                 :             : 
     849                 :             : static_assert(_BF_HOOK_MAX <= 8 * sizeof(uint32_t),
     850                 :             :               "too many hooks for unsupported_hooks bitmask");
     851                 :             : 
     852                 :             : /* TCP (RFC 9293, section 3.1) and UDP (RFC 768, "Format") define their
     853                 :             :  * first 32 bits identically:
     854                 :             :  *
     855                 :             :  *     | Source Port (16 bits) | Destination Port (16 bits) |
     856                 :             :  *
     857                 :             :  * https://www.rfc-editor.org/rfc/rfc9293.html#section-3.1
     858                 :             :  * https://www.rfc-editor.org/rfc/rfc768.html
     859                 :             :  *
     860                 :             :  * Packet META port matching relies on this common wire layout. */
     861                 :             : static_assert(offsetof(struct tcphdr, source) ==
     862                 :             :                   offsetof(struct udphdr, source),
     863                 :             :               "TCP and UDP source port offsets must match");
     864                 :             : static_assert(offsetof(struct tcphdr, dest) == offsetof(struct udphdr, dest),
     865                 :             :               "TCP and UDP destination port offsets must match");
     866                 :             : 
     867                 :             : // Comma-separated cgroup_sock_addr hook lists, for use inside `BF_FLAGS()`.
     868                 :             : #define _BF_HOOKS_CGROUP_SOCK_ADDR_IP4                                         \
     869                 :             :     BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4, BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG4
     870                 :             : #define _BF_HOOKS_CGROUP_SOCK_ADDR_IP6                                         \
     871                 :             :     BF_HOOK_CGROUP_SOCK_ADDR_CONNECT6, BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG6
     872                 :             : #define _BF_HOOKS_CGROUP_SOCK_ADDR_ALL                                         \
     873                 :             :     _BF_HOOKS_CGROUP_SOCK_ADDR_IP4, _BF_HOOKS_CGROUP_SOCK_ADDR_IP6
     874                 :             : 
     875                 :             : static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
     876                 :             :     [BF_MATCHER_META_IFACE] =
     877                 :             :         {
     878                 :             :             .layer = BF_MATCHER_NO_LAYER,
     879                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
     880                 :             :             .ops =
     881                 :             :                 {
     882                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     883                 :             :                                    _bf_parse_iface, _bf_print_iface),
     884                 :             :                 },
     885                 :             :         },
     886                 :             :     [BF_MATCHER_META_L3_PROTO] =
     887                 :             :         {
     888                 :             :             .layer = BF_MATCHER_NO_LAYER,
     889                 :             :             .ops =
     890                 :             :                 {
     891                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     892                 :             :                                    _bf_parse_l3_proto, _bf_print_l3_proto),
     893                 :             :                 },
     894                 :             :         },
     895                 :             :     [BF_MATCHER_META_L4_PROTO] =
     896                 :             :         {
     897                 :             :             .layer = BF_MATCHER_NO_LAYER,
     898                 :             :             .ops =
     899                 :             :                 {
     900                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     901                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     902                 :             :                 },
     903                 :             :         },
     904                 :             :     [BF_MATCHER_META_SPORT] =
     905                 :             :         {
     906                 :             :             .layer = BF_MATCHER_NO_LAYER,
     907                 :             :             .hdr_payload_size = sizeof(uint16_t),
     908                 :             :             // TCP and UDP share this offset, as asserted above.
     909                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, source),
     910                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
     911                 :             :             .ops =
     912                 :             :                 {
     913                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     914                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     915                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
     916                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     917                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     918                 :             :                                    _bf_parse_l4_port_range,
     919                 :             :                                    _bf_print_l4_port_range),
     920                 :             :                 },
     921                 :             :         },
     922                 :             :     [BF_MATCHER_META_DPORT] =
     923                 :             :         {
     924                 :             :             .layer = BF_MATCHER_NO_LAYER,
     925                 :             :             .hdr_payload_size = sizeof(uint16_t),
     926                 :             :             // TCP and UDP share this offset, as asserted above.
     927                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, dest),
     928                 :             :             .ops =
     929                 :             :                 {
     930                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     931                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     932                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
     933                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
     934                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     935                 :             :                                    _bf_parse_l4_port_range,
     936                 :             :                                    _bf_print_l4_port_range),
     937                 :             :                 },
     938                 :             :         },
     939                 :             :     [BF_MATCHER_META_PROBABILITY] =
     940                 :             :         {
     941                 :             :             .layer = BF_MATCHER_NO_LAYER,
     942                 :             :             .ops =
     943                 :             :                 {
     944                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(float),
     945                 :             :                                    _bf_parse_probability,
     946                 :             :                                    _bf_print_probability),
     947                 :             :                 },
     948                 :             :         },
     949                 :             :     [BF_MATCHER_META_MARK] =
     950                 :             :         {
     951                 :             :             .layer = BF_MATCHER_NO_LAYER,
     952                 :             :             .unsupported_hooks =
     953                 :             :                 BF_FLAGS(BF_HOOK_XDP, _BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
     954                 :             :             .ops =
     955                 :             :                 {
     956                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     957                 :             :                                    _bf_parse_mark, _bf_print_mark),
     958                 :             :                 },
     959                 :             :         },
     960                 :             :     [BF_MATCHER_META_FLOW_HASH] =
     961                 :             :         {
     962                 :             :             .layer = BF_MATCHER_NO_LAYER,
     963                 :             :             .unsupported_hooks =
     964                 :             :                 BF_FLAGS(BF_HOOK_XDP, BF_HOOK_CGROUP_SKB_INGRESS,
     965                 :             :                          BF_HOOK_CGROUP_SKB_EGRESS, BF_HOOK_NF_FORWARD,
     966                 :             :                          BF_HOOK_NF_LOCAL_IN, BF_HOOK_NF_LOCAL_OUT,
     967                 :             :                          BF_HOOK_NF_POST_ROUTING, BF_HOOK_NF_PRE_ROUTING,
     968                 :             :                          _BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
     969                 :             :             .ops =
     970                 :             :                 {
     971                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     972                 :             :                                    _bf_parse_u32, _bf_print_u32),
     973                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint32_t),
     974                 :             :                                    _bf_parse_u32_range, _bf_print_u32_range),
     975                 :             :                 },
     976                 :             :         },
     977                 :             :     [BF_MATCHER_META_FLOW_PROBABILITY] =
     978                 :             :         {
     979                 :             :             .layer = BF_MATCHER_NO_LAYER,
     980                 :             :             .unsupported_hooks = BF_FLAGS(
     981                 :             :                 BF_HOOK_NF_FORWARD, BF_HOOK_NF_LOCAL_IN, BF_HOOK_NF_LOCAL_OUT,
     982                 :             :                 BF_HOOK_NF_POST_ROUTING, BF_HOOK_NF_PRE_ROUTING,
     983                 :             :                 _BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
     984                 :             :             .ops =
     985                 :             :                 {
     986                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(float),
     987                 :             :                                    _bf_parse_probability,
     988                 :             :                                    _bf_print_probability),
     989                 :             :                 },
     990                 :             :         },
     991                 :             :     [BF_MATCHER_META_PID] =
     992                 :             :         {
     993                 :             :             .layer = BF_MATCHER_NO_LAYER,
     994                 :             :             .hdr_payload_size = sizeof(uint32_t),
     995                 :             :             .unsupported_hooks = BF_FLAGS_MASK(_BF_HOOK_MAX) &
     996                 :             :                                  ~(BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL)),
     997                 :             :             .ops =
     998                 :             :                 {
     999                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
    1000                 :             :                                    _bf_parse_pid, _bf_print_pid),
    1001                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
    1002                 :             :                                    _bf_parse_pid, _bf_print_pid),
    1003                 :             :                 },
    1004                 :             :         },
    1005                 :             :     [BF_MATCHER_IP4_SADDR] =
    1006                 :             :         {
    1007                 :             :             .layer = BF_MATCHER_LAYER_3,
    1008                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP6,
    1009                 :             :                                           BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4),
    1010                 :             :             .hdr_id = ETH_P_IP,
    1011                 :             :             .hdr_payload_size = sizeof(uint32_t),
    1012                 :             :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
    1013                 :             :             .ops =
    1014                 :             :                 {
    1015                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
    1016                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
    1017                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
    1018                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
    1019                 :             :                 },
    1020                 :             :         },
    1021                 :             :     [BF_MATCHER_IP4_DADDR] =
    1022                 :             :         {
    1023                 :             :             .layer = BF_MATCHER_LAYER_3,
    1024                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP6),
    1025                 :             :             .hdr_id = ETH_P_IP,
    1026                 :             :             .hdr_payload_size = sizeof(uint32_t),
    1027                 :             :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
    1028                 :             :             .ops =
    1029                 :             :                 {
    1030                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
    1031                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
    1032                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
    1033                 :             :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
    1034                 :             :                 },
    1035                 :             :         },
    1036                 :             :     [BF_MATCHER_IP4_SNET] =
    1037                 :             :         {
    1038                 :             :             .layer = BF_MATCHER_LAYER_3,
    1039                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP6,
    1040                 :             :                                           BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4),
    1041                 :             :             .hdr_id = ETH_P_IP,
    1042                 :             :             .hdr_payload_size = sizeof(uint32_t),
    1043                 :             :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
    1044                 :             :             .ops =
    1045                 :             :                 {
    1046                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
    1047                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
    1048                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
    1049                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
    1050                 :             :                 },
    1051                 :             :         },
    1052                 :             :     [BF_MATCHER_IP4_DNET] =
    1053                 :             :         {
    1054                 :             :             .layer = BF_MATCHER_LAYER_3,
    1055                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP6),
    1056                 :             :             .hdr_id = ETH_P_IP,
    1057                 :             :             .hdr_payload_size = sizeof(uint32_t),
    1058                 :             :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
    1059                 :             :             .ops =
    1060                 :             :                 {
    1061                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
    1062                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
    1063                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
    1064                 :             :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
    1065                 :             :                 },
    1066                 :             :         },
    1067                 :             :     [BF_MATCHER_IP4_PROTO] =
    1068                 :             :         {
    1069                 :             :             .layer = BF_MATCHER_LAYER_3,
    1070                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP6),
    1071                 :             :             .hdr_id = ETH_P_IP,
    1072                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1073                 :             :             .hdr_payload_offset = offsetof(struct iphdr, protocol),
    1074                 :             :             .ops =
    1075                 :             :                 {
    1076                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1077                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1078                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1079                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1080                 :             :                 },
    1081                 :             :         },
    1082                 :             :     [BF_MATCHER_IP4_DSCP] =
    1083                 :             :         {
    1084                 :             :             .layer = BF_MATCHER_LAYER_3,
    1085                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1086                 :             :             .hdr_id = ETH_P_IP,
    1087                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1088                 :             :             .hdr_payload_offset = offsetof(struct iphdr, tos),
    1089                 :             :             .ops =
    1090                 :             :                 {
    1091                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1092                 :             :                                    _bf_parse_dscp, _bf_print_dscp),
    1093                 :             :                 },
    1094                 :             :         },
    1095                 :             :     [BF_MATCHER_IP6_SADDR] =
    1096                 :             :         {
    1097                 :             :             .layer = BF_MATCHER_LAYER_3,
    1098                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP4,
    1099                 :             :                                           BF_HOOK_CGROUP_SOCK_ADDR_CONNECT6),
    1100                 :             :             .hdr_id = ETH_P_IPV6,
    1101                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1102                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
    1103                 :             :             .ops =
    1104                 :             :                 {
    1105                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
    1106                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
    1107                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
    1108                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
    1109                 :             :                 },
    1110                 :             :         },
    1111                 :             :     [BF_MATCHER_IP6_DADDR] =
    1112                 :             :         {
    1113                 :             :             .layer = BF_MATCHER_LAYER_3,
    1114                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP4),
    1115                 :             :             .hdr_id = ETH_P_IPV6,
    1116                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1117                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
    1118                 :             :             .ops =
    1119                 :             :                 {
    1120                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
    1121                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
    1122                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
    1123                 :             :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
    1124                 :             :                 },
    1125                 :             :         },
    1126                 :             :     [BF_MATCHER_IP6_SNET] =
    1127                 :             :         {
    1128                 :             :             .layer = BF_MATCHER_LAYER_3,
    1129                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP4,
    1130                 :             :                                           BF_HOOK_CGROUP_SOCK_ADDR_CONNECT6),
    1131                 :             :             .hdr_id = ETH_P_IPV6,
    1132                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1133                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
    1134                 :             :             .ops =
    1135                 :             :                 {
    1136                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
    1137                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1138                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
    1139                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1140                 :             :                 },
    1141                 :             :         },
    1142                 :             :     [BF_MATCHER_IP6_DNET] =
    1143                 :             :         {
    1144                 :             :             .layer = BF_MATCHER_LAYER_3,
    1145                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_IP4),
    1146                 :             :             .hdr_id = ETH_P_IPV6,
    1147                 :             :             .hdr_payload_size = sizeof(struct in6_addr),
    1148                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
    1149                 :             :             .ops =
    1150                 :             :                 {
    1151                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
    1152                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1153                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
    1154                 :             :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
    1155                 :             :                 },
    1156                 :             :         },
    1157                 :             :     [BF_MATCHER_IP6_NEXTHDR] =
    1158                 :             :         {
    1159                 :             :             .layer = BF_MATCHER_LAYER_3,
    1160                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1161                 :             :             .hdr_id = ETH_P_IPV6,
    1162                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1163                 :             :             .hdr_payload_offset = offsetof(struct ipv6hdr, nexthdr),
    1164                 :             :             .ops =
    1165                 :             :                 {
    1166                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1167                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1168                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1169                 :             :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
    1170                 :             :                 },
    1171                 :             :         },
    1172                 :             :     [BF_MATCHER_IP6_DSCP] =
    1173                 :             :         {
    1174                 :             :             .layer = BF_MATCHER_LAYER_3,
    1175                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1176                 :             :             .hdr_id = ETH_P_IPV6,
    1177                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1178                 :             :             .hdr_payload_offset = 0,
    1179                 :             :             .ops =
    1180                 :             :                 {
    1181                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1182                 :             :                                    _bf_parse_dscp, _bf_print_dscp),
    1183                 :             :                 },
    1184                 :             :         },
    1185                 :             :     [BF_MATCHER_TCP_SPORT] =
    1186                 :             :         {
    1187                 :             :             .layer = BF_MATCHER_LAYER_4,
    1188                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1189                 :             :             .hdr_id = IPPROTO_TCP,
    1190                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1191                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, source),
    1192                 :             :             .ops =
    1193                 :             :                 {
    1194                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1195                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1196                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1197                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1198                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1199                 :             :                                    _bf_parse_l4_port_range,
    1200                 :             :                                    _bf_print_l4_port_range),
    1201                 :             :                 },
    1202                 :             :         },
    1203                 :             :     [BF_MATCHER_TCP_DPORT] =
    1204                 :             :         {
    1205                 :             :             .layer = BF_MATCHER_LAYER_4,
    1206                 :             :             .unsupported_hooks = BF_FLAGS(BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG4,
    1207                 :             :                                           BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG6),
    1208                 :             :             .hdr_id = IPPROTO_TCP,
    1209                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1210                 :             :             .hdr_payload_offset = offsetof(struct tcphdr, dest),
    1211                 :             :             .ops =
    1212                 :             :                 {
    1213                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1214                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1215                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1216                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1217                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1218                 :             :                                    _bf_parse_l4_port_range,
    1219                 :             :                                    _bf_print_l4_port_range),
    1220                 :             :                 },
    1221                 :             :         },
    1222                 :             :     [BF_MATCHER_TCP_FLAGS] =
    1223                 :             :         {
    1224                 :             :             .layer = BF_MATCHER_LAYER_4,
    1225                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1226                 :             :             .hdr_id = IPPROTO_TCP,
    1227                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1228                 :             :             .hdr_payload_offset = _BF_TCP_FLAGS_OFFSET,
    1229                 :             :             .ops =
    1230                 :             :                 {
    1231                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1232                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1233                 :             :                     BF_MATCHER_OPS(BF_MATCHER_ANY, sizeof(uint8_t),
    1234                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1235                 :             :                     BF_MATCHER_OPS(BF_MATCHER_ALL, sizeof(uint8_t),
    1236                 :             :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
    1237                 :             :                 },
    1238                 :             :         },
    1239                 :             :     [BF_MATCHER_UDP_SPORT] =
    1240                 :             :         {
    1241                 :             :             .layer = BF_MATCHER_LAYER_4,
    1242                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1243                 :             :             .hdr_id = IPPROTO_UDP,
    1244                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1245                 :             :             .hdr_payload_offset = offsetof(struct udphdr, source),
    1246                 :             :             .ops =
    1247                 :             :                 {
    1248                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1249                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1250                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1251                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1252                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1253                 :             :                                    _bf_parse_l4_port_range,
    1254                 :             :                                    _bf_print_l4_port_range),
    1255                 :             :                 },
    1256                 :             :         },
    1257                 :             :     [BF_MATCHER_UDP_DPORT] =
    1258                 :             :         {
    1259                 :             :             .layer = BF_MATCHER_LAYER_4,
    1260                 :             :             .hdr_id = IPPROTO_UDP,
    1261                 :             :             .hdr_payload_size = sizeof(uint16_t),
    1262                 :             :             .hdr_payload_offset = offsetof(struct udphdr, dest),
    1263                 :             :             .ops =
    1264                 :             :                 {
    1265                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1266                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1267                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1268                 :             :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1269                 :             :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1270                 :             :                                    _bf_parse_l4_port_range,
    1271                 :             :                                    _bf_print_l4_port_range),
    1272                 :             :                 },
    1273                 :             :         },
    1274                 :             :     [BF_MATCHER_ICMP_TYPE] =
    1275                 :             :         {
    1276                 :             :             .layer = BF_MATCHER_LAYER_4,
    1277                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1278                 :             :             .hdr_id = IPPROTO_ICMP,
    1279                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1280                 :             :             .hdr_payload_offset = offsetof(struct icmphdr, type),
    1281                 :             :             .ops =
    1282                 :             :                 {
    1283                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1284                 :             :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1285                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1286                 :             :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1287                 :             :                 },
    1288                 :             :         },
    1289                 :             :     [BF_MATCHER_ICMP_CODE] =
    1290                 :             :         {
    1291                 :             :             .layer = BF_MATCHER_LAYER_4,
    1292                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1293                 :             :             .hdr_id = IPPROTO_ICMP,
    1294                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1295                 :             :             .hdr_payload_offset = offsetof(struct icmphdr, code),
    1296                 :             :             .ops =
    1297                 :             :                 {
    1298                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1299                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1300                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1301                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1302                 :             :                 },
    1303                 :             :         },
    1304                 :             :     [BF_MATCHER_ICMPV6_TYPE] =
    1305                 :             :         {
    1306                 :             :             .layer = BF_MATCHER_LAYER_4,
    1307                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1308                 :             :             .hdr_id = IPPROTO_ICMPV6,
    1309                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1310                 :             :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_type),
    1311                 :             :             .ops =
    1312                 :             :                 {
    1313                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1314                 :             :                                    _bf_parse_icmpv6_type,
    1315                 :             :                                    _bf_print_icmpv6_type),
    1316                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1317                 :             :                                    _bf_parse_icmpv6_type,
    1318                 :             :                                    _bf_print_icmpv6_type),
    1319                 :             :                 },
    1320                 :             :         },
    1321                 :             :     [BF_MATCHER_ICMPV6_CODE] =
    1322                 :             :         {
    1323                 :             :             .layer = BF_MATCHER_LAYER_4,
    1324                 :             :             .unsupported_hooks = BF_FLAGS(_BF_HOOKS_CGROUP_SOCK_ADDR_ALL),
    1325                 :             :             .hdr_id = IPPROTO_ICMPV6,
    1326                 :             :             .hdr_payload_size = sizeof(uint8_t),
    1327                 :             :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_code),
    1328                 :             :             .ops =
    1329                 :             :                 {
    1330                 :             :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1331                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1332                 :             :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1333                 :             :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1334                 :             :                 },
    1335                 :             :         },
    1336                 :             :     [BF_MATCHER_SET] =
    1337                 :             :         {
    1338                 :             :             .layer = BF_MATCHER_NO_LAYER,
    1339                 :             :         },
    1340                 :             : };
    1341                 :             : 
    1342                 :       40918 : const struct bf_matcher_meta *bf_matcher_get_meta(enum bf_matcher_type type)
    1343                 :             : {
    1344         [ +  - ]:       40918 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1345                 :             :         return NULL;
    1346                 :             : 
    1347                 :       40918 :     return _bf_matcher_metas[type].layer == _BF_MATCHER_LAYER_UNDEFINED ?
    1348         [ +  - ]:       40918 :                NULL :
    1349                 :             :                &_bf_matcher_metas[type];
    1350                 :             : }
    1351                 :             : 
    1352                 :        6907 : const struct bf_matcher_ops *bf_matcher_get_ops(enum bf_matcher_type type,
    1353                 :             :                                                 enum bf_matcher_op op)
    1354                 :             : {
    1355                 :        6907 :     const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
    1356                 :             : 
    1357         [ +  - ]:        6907 :     if (!meta)
    1358                 :             :         return NULL;
    1359                 :             : 
    1360         [ +  + ]:        6907 :     return meta->ops[op].ref_payload_size ? &meta->ops[op] : NULL;
    1361                 :             : }
    1362                 :             : 
    1363                 :       10498 : static int _bf_matcher_new(struct bf_matcher **matcher,
    1364                 :             :                            enum bf_matcher_type type, enum bf_matcher_op op,
    1365                 :             :                            const void *payload, size_t payload_len, bool negate)
    1366                 :             : {
    1367                 :       10498 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1368                 :             : 
    1369                 :             :     assert(matcher);
    1370                 :             :     assert((payload && payload_len) || (!payload && !payload_len));
    1371                 :             : 
    1372   [ +  +  +  -  :       10498 :     if (type == BF_MATCHER_SET && (op != BF_MATCHER_IN || !payload ||
                   -  + ]
    1373                 :             :                                    payload_len != sizeof(struct bf_set *)))
    1374         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "invalid set matcher payload or operator");
    1375                 :             : 
    1376         [ +  - ]:        8322 :     if (payload_len > SIZE_MAX - sizeof(*_matcher))
    1377                 :             :         return -E2BIG;
    1378                 :             : 
    1379                 :       10498 :     _matcher = calloc(1, sizeof(struct bf_matcher) + payload_len);
    1380         [ +  - ]:       10498 :     if (!_matcher)
    1381                 :             :         return -ENOMEM;
    1382                 :             : 
    1383                 :       10498 :     _matcher->type = type;
    1384                 :       10498 :     _matcher->op = op;
    1385                 :       10498 :     _matcher->negate = negate;
    1386                 :       10498 :     _matcher->len = sizeof(struct bf_matcher) + payload_len;
    1387                 :       10498 :     bf_memcpy(_matcher->payload, payload, payload_len);
    1388                 :             : 
    1389                 :       10498 :     *matcher = TAKE_PTR(_matcher);
    1390                 :             : 
    1391                 :       10498 :     return 0;
    1392                 :             : }
    1393                 :             : 
    1394                 :        5751 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
    1395                 :             :                    enum bf_matcher_op op, const void *payload,
    1396                 :             :                    size_t payload_len, bool negate)
    1397                 :             : {
    1398                 :             :     assert(matcher);
    1399                 :             : 
    1400         [ +  + ]:        5751 :     if (type == BF_MATCHER_SET)
    1401         [ +  - ]:           7 :         return bf_err_r(-EINVAL, "use a set matcher constructor");
    1402                 :             : 
    1403                 :        5744 :     return _bf_matcher_new(matcher, type, op, payload, payload_len, negate);
    1404                 :             : }
    1405                 :             : 
    1406                 :         281 : int bf_matcher_new_for_named_set(struct bf_matcher **matcher,
    1407                 :             :                                  const struct bf_set *set, bool negate)
    1408                 :             : {
    1409                 :             :     assert(matcher);
    1410                 :             : 
    1411   [ +  +  +  + ]:         281 :     if (!set || !bf_set_is_valid_name(set->name))
    1412         [ +  - ]:           3 :         return bf_err_r(-EINVAL, "set matcher requires a named set");
    1413                 :             : 
    1414                 :         278 :     return _bf_matcher_new(matcher, BF_MATCHER_SET, BF_MATCHER_IN, &set,
    1415                 :             :                            sizeof(struct bf_set *), negate);
    1416                 :             : }
    1417                 :             : 
    1418                 :        1898 : static int _bf_matcher_new_for_anon_set(struct bf_matcher **matcher,
    1419                 :             :                                         struct bf_set **set, bool negate)
    1420                 :             : {
    1421                 :             :     int r;
    1422                 :             : 
    1423                 :             :     assert(matcher);
    1424                 :             :     assert(set && *set);
    1425                 :             : 
    1426                 :        1898 :     r = _bf_matcher_new(matcher, BF_MATCHER_SET, BF_MATCHER_IN, set,
    1427                 :             :                         sizeof(struct bf_set *), negate);
    1428         [ +  - ]:        1898 :     if (r)
    1429                 :             :         return r;
    1430                 :             : 
    1431                 :        1898 :     TAKE_PTR(*set);
    1432                 :             : 
    1433                 :        1898 :     return 0;
    1434                 :             : }
    1435                 :             : 
    1436                 :         235 : int bf_matcher_new_for_anon_set(struct bf_matcher **matcher,
    1437                 :             :                                 const enum bf_matcher_type *key, size_t n_comps,
    1438                 :             :                                 const void * const *elems, size_t n_elems,
    1439                 :             :                                 bool negate)
    1440                 :             : {
    1441                 :         235 :     _free_bf_set_ struct bf_set *set = NULL;
    1442                 :             :     int r;
    1443                 :             : 
    1444                 :             :     assert(matcher);
    1445                 :             :     assert(key);
    1446                 :             : 
    1447         [ +  + ]:         235 :     if (n_elems && !elems)
    1448         [ +  - ]:           1 :         return bf_err_r(-EINVAL, "missing anonymous set elements");
    1449                 :             : 
    1450                 :         234 :     r = bf_set_new(&set, NULL, key, n_comps);
    1451         [ +  + ]:         234 :     if (r)
    1452                 :             :         return r;
    1453                 :             : 
    1454                 :         233 :     r = bf_set_reserve(set, n_elems);
    1455         [ +  - ]:         233 :     if (r)
    1456                 :             :         return r;
    1457                 :             : 
    1458         [ +  + ]:         647 :     for (size_t i = 0; i < n_elems; ++i) {
    1459         [ +  + ]:         415 :         if (!elems[i])
    1460         [ +  - ]:           1 :             return bf_err_r(-EINVAL, "missing anonymous set element");
    1461                 :             : 
    1462                 :         414 :         r = bf_set_add_elem(set, elems[i]);
    1463         [ +  - ]:         414 :         if (r)
    1464                 :             :             return r;
    1465                 :             :     }
    1466                 :             : 
    1467                 :         232 :     return _bf_matcher_new_for_anon_set(matcher, &set, negate);
    1468                 :             : }
    1469                 :             : 
    1470                 :         183 : int bf_matcher_new_for_anon_set_from_raw(struct bf_matcher **matcher,
    1471                 :             :                                          const char *raw_key,
    1472                 :             :                                          const char *raw_payload, bool negate)
    1473                 :             : {
    1474                 :         183 :     _free_bf_set_ struct bf_set *set = NULL;
    1475                 :             :     int r;
    1476                 :             : 
    1477                 :             :     assert(matcher);
    1478                 :             :     assert(raw_key);
    1479                 :             :     assert(raw_payload);
    1480                 :             : 
    1481                 :         183 :     r = bf_set_new_from_raw(&set, NULL, raw_key, raw_payload);
    1482         [ +  + ]:         183 :     if (r)
    1483                 :             :         return r;
    1484                 :             : 
    1485                 :         172 :     return _bf_matcher_new_for_anon_set(matcher, &set, negate);
    1486                 :             : }
    1487                 :             : 
    1488                 :        2706 : int bf_matcher_new_from_raw(struct bf_matcher **matcher,
    1489                 :             :                             enum bf_matcher_type type, enum bf_matcher_op op,
    1490                 :             :                             const char *payload, bool negate)
    1491                 :             : {
    1492                 :        2706 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1493                 :             :     const struct bf_matcher_ops *ops;
    1494                 :             :     int r;
    1495                 :             : 
    1496                 :             :     assert(matcher);
    1497                 :             :     assert(payload);
    1498                 :             : 
    1499                 :        2706 :     ops = bf_matcher_get_ops(type, op);
    1500         [ -  + ]:        2706 :     if (!ops) {
    1501         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "payload ops not found for '%s %s'",
    1502                 :             :                         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op));
    1503                 :             :     }
    1504                 :             : 
    1505                 :        2706 :     _matcher = calloc(1, sizeof(*_matcher) + ops->ref_payload_size);
    1506         [ +  - ]:        2706 :     if (!_matcher)
    1507                 :             :         return -ENOMEM;
    1508                 :             : 
    1509                 :        2706 :     _matcher->type = type;
    1510                 :        2706 :     _matcher->op = op;
    1511                 :        2706 :     _matcher->negate = negate;
    1512                 :        2706 :     _matcher->len = sizeof(*_matcher) + ops->ref_payload_size;
    1513                 :             : 
    1514                 :        2706 :     r = ops->parse(_matcher->type, _matcher->op, &_matcher->payload, payload);
    1515         [ +  + ]:        2706 :     if (r)
    1516                 :             :         return r;
    1517                 :             : 
    1518                 :        2244 :     *matcher = TAKE_PTR(_matcher);
    1519                 :             : 
    1520                 :        2244 :     return 0;
    1521                 :             : }
    1522                 :             : 
    1523                 :        5847 : int bf_matcher_new_from_pack(struct bf_matcher **matcher, bf_rpack_node_t node,
    1524                 :             :                              const bf_hashset *sets)
    1525                 :             : {
    1526                 :        5847 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1527                 :        5847 :     _cleanup_free_ char *set_name = NULL;
    1528                 :             :     enum bf_matcher_type type;
    1529                 :             :     enum bf_matcher_op op;
    1530                 :             :     const void *payload;
    1531                 :             :     size_t payload_len;
    1532                 :        5847 :     bool negate = false;
    1533                 :             :     int r;
    1534                 :             : 
    1535                 :             :     assert(matcher);
    1536                 :             : 
    1537   [ -  +  -  +  :        5847 :     r = bf_rpack_kv_enum(node, "type", &type, 0, _BF_MATCHER_TYPE_MAX);
                   -  - ]
    1538                 :             :     if (r)
    1539         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_matcher.type");
    1540                 :             : 
    1541   [ -  +  -  +  :        5847 :     r = bf_rpack_kv_enum(node, "op", &op, 0, _BF_MATCHER_OP_MAX);
                   -  - ]
    1542                 :             :     if (r)
    1543         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_matcher.op");
    1544                 :             : 
    1545         [ +  + ]:        5847 :     if (bf_rpack_kv_contains(node, "negate")) {
    1546                 :        5845 :         r = bf_rpack_kv_bool(node, "negate", &negate);
    1547         [ -  + ]:        5845 :         if (r)
    1548         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_matcher.negate");
    1549                 :             :     }
    1550                 :             : 
    1551         [ +  + ]:        5847 :     if (type == BF_MATCHER_SET) {
    1552                 :             :         const struct bf_set *set;
    1553                 :             : 
    1554         [ -  + ]:        1263 :         if (op != BF_MATCHER_IN)
    1555         [ #  # ]:           0 :             return bf_err_r(-EINVAL, "invalid set matcher operator");
    1556                 :             : 
    1557         [ +  + ]:        1263 :         if (bf_rpack_kv_contains(node, "set")) {
    1558                 :        1162 :             _free_bf_set_ struct bf_set *anonymous = NULL;
    1559                 :             :             bf_rpack_node_t set_node;
    1560                 :             : 
    1561         [ -  + ]:        1162 :             if (bf_rpack_kv_contains(node, "payload"))
    1562         [ #  # ]:           0 :                 return bf_err_r(-EINVAL, "ambiguous set matcher payload");
    1563                 :             : 
    1564                 :        1162 :             r = bf_rpack_kv_obj(node, "set", &set_node);
    1565         [ -  + ]:        1162 :             if (r)
    1566         [ #  # ]:           0 :                 return bf_rpack_key_err(r, "bf_matcher.set");
    1567                 :             : 
    1568                 :        1162 :             r = bf_set_new_from_pack(&anonymous, set_node);
    1569         [ +  - ]:        1162 :             if (r)
    1570                 :             :                 return r;
    1571         [ -  + ]:        1162 :             if (!bf_set_is_anonymous(anonymous)) {
    1572         [ #  # ]:           0 :                 return bf_err_r(-EINVAL,
    1573                 :             :                                 "inline matcher set must be anonymous");
    1574                 :             :             }
    1575                 :             : 
    1576                 :        1162 :             return _bf_matcher_new_for_anon_set(matcher, &anonymous, negate);
    1577                 :             :         }
    1578                 :             : 
    1579                 :         101 :         r = bf_rpack_kv_str(node, "payload", &set_name);
    1580         [ +  + ]:         101 :         if (r)
    1581         [ +  - ]:           1 :             return bf_rpack_key_err(r, "bf_matcher.payload");
    1582                 :             : 
    1583   [ +  +  -  + ]:         198 :         if (!sets ||
    1584                 :          98 :             !(set = bf_hashset_get(sets, &(struct bf_set) {.name = set_name})))
    1585         [ +  - ]:           2 :             return bf_err_r(-ENOENT, "set '%s' not found", set_name);
    1586                 :             : 
    1587                 :          98 :         payload = set;
    1588                 :          98 :         payload_len = sizeof(*set);
    1589                 :             :     } else {
    1590                 :        4584 :         r = bf_rpack_kv_bin(node, "payload", &payload, &payload_len);
    1591         [ -  + ]:        4584 :         if (r)
    1592         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_matcher.payload");
    1593                 :             :     }
    1594                 :             : 
    1595         [ +  + ]:        4682 :     if (type == BF_MATCHER_SET)
    1596                 :          98 :         r = bf_matcher_new_for_named_set(&_matcher, payload, negate);
    1597                 :             :     else
    1598                 :        4584 :         r = bf_matcher_new(&_matcher, type, op, payload, payload_len, negate);
    1599         [ -  + ]:        4682 :     if (r)
    1600         [ #  # ]:           0 :         return bf_err_r(r, "failed to create bf_matcher from pack");
    1601                 :             : 
    1602                 :        4682 :     *matcher = TAKE_PTR(_matcher);
    1603                 :             : 
    1604                 :        4682 :     return 0;
    1605                 :             : }
    1606                 :             : 
    1607                 :        2989 : int bf_matcher_new_from_copy(struct bf_matcher **dest,
    1608                 :             :                              const struct bf_matcher *src)
    1609                 :             : {
    1610                 :             :     size_t payload_len;
    1611                 :             : 
    1612                 :             :     assert(dest);
    1613                 :             :     assert(src);
    1614                 :             : 
    1615         [ +  - ]:        2989 :     if (src->type < 0 || src->type >= _BF_MATCHER_TYPE_MAX || src->op < 0 ||
    1616   [ +  -  -  + ]:        2989 :         src->op >= _BF_MATCHER_OP_MAX || src->len < sizeof(*src)) {
    1617         [ #  # ]:           0 :         return bf_err_r(-EINVAL,
    1618                 :             :                         "invalid source matcher type, operator, or length");
    1619                 :             :     }
    1620                 :             : 
    1621                 :        2989 :     payload_len = src->len - sizeof(*src);
    1622                 :             : 
    1623         [ +  + ]:        2989 :     if (src->type == BF_MATCHER_SET) {
    1624                 :             :         const struct bf_set *set;
    1625                 :             : 
    1626   [ +  -  -  + ]:         411 :         if (src->op != BF_MATCHER_IN || payload_len != sizeof(struct bf_set *))
    1627         [ #  # ]:           0 :             return bf_err_r(-EINVAL,
    1628                 :             :                             "invalid source set matcher payload or operator");
    1629                 :             : 
    1630                 :         411 :         memcpy(&set, src->payload, sizeof(struct bf_set *));
    1631         [ -  + ]:         411 :         if (!set)
    1632         [ #  # ]:           0 :             return bf_err_r(-EINVAL, "missing source set matcher payload");
    1633                 :             : 
    1634         [ +  + ]:         411 :         if (bf_set_is_anonymous(set)) {
    1635                 :         332 :             _free_bf_set_ struct bf_set *copy = NULL;
    1636                 :             :             int r;
    1637                 :             : 
    1638                 :         332 :             r = bf_set_new_from_copy(&copy, set);
    1639         [ +  - ]:         332 :             if (r)
    1640                 :             :                 return r;
    1641                 :             : 
    1642                 :         332 :             return _bf_matcher_new_for_anon_set(dest, &copy, src->negate);
    1643                 :             :         }
    1644                 :             : 
    1645                 :          79 :         return bf_matcher_new_for_named_set(dest, set, src->negate);
    1646                 :             :     }
    1647                 :             : 
    1648                 :        2578 :     return _bf_matcher_new(dest, src->type, src->op,
    1649                 :             :                            payload_len ? src->payload : NULL, payload_len,
    1650         [ +  + ]:        2578 :                            src->negate);
    1651                 :             : }
    1652                 :             : 
    1653                 :       46028 : void bf_matcher_free(struct bf_matcher **matcher)
    1654                 :             : {
    1655                 :             :     assert(matcher);
    1656                 :             : 
    1657         [ +  + ]:       46028 :     if (!*matcher)
    1658                 :             :         return;
    1659                 :             : 
    1660         [ +  + ]:       13204 :     if ((*matcher)->type == BF_MATCHER_SET) {
    1661                 :             :         struct bf_set *set;
    1662                 :             : 
    1663                 :        2176 :         memcpy(&set, (*matcher)->payload, sizeof(struct bf_set *));
    1664         [ +  + ]:        2176 :         if (bf_set_is_anonymous(set))
    1665                 :        1898 :             bf_set_free(&set);
    1666                 :             :     }
    1667                 :             : 
    1668                 :       13204 :     free(*matcher);
    1669                 :       13204 :     *matcher = NULL;
    1670                 :             : }
    1671                 :             : 
    1672                 :        3029 : int bf_matcher_pack(const struct bf_matcher *matcher, bf_wpack_t *pack)
    1673                 :             : {
    1674                 :             :     assert(matcher);
    1675                 :             :     assert(pack);
    1676                 :             : 
    1677                 :        3029 :     bf_wpack_kv_int(pack, "type", matcher->type);
    1678                 :        3029 :     bf_wpack_kv_int(pack, "op", matcher->op);
    1679                 :        3029 :     bf_wpack_kv_bool(pack, "negate", matcher->negate);
    1680         [ +  + ]:        3029 :     if (matcher->type == BF_MATCHER_SET) {
    1681                 :             :         const struct bf_set *set;
    1682                 :             : 
    1683                 :         426 :         memcpy(&set, matcher->payload, sizeof(struct bf_set *));
    1684         [ +  + ]:         426 :         if (bf_set_is_anonymous(set)) {
    1685                 :             :             int r;
    1686                 :             : 
    1687                 :         332 :             bf_wpack_open_object(pack, "set");
    1688                 :         332 :             r = bf_set_pack(set, pack);
    1689         [ +  - ]:         332 :             if (r)
    1690                 :             :                 return r;
    1691                 :         332 :             bf_wpack_close_object(pack);
    1692                 :             :         } else {
    1693                 :          94 :             bf_wpack_kv_str(pack, "payload", set->name);
    1694                 :             :         }
    1695                 :             :     } else {
    1696                 :        2603 :         bf_wpack_kv_bin(pack, "payload", matcher->payload,
    1697                 :        2603 :                         matcher->len - sizeof(*matcher));
    1698                 :             :     }
    1699                 :             : 
    1700         [ -  + ]:        3029 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
    1701                 :             : }
    1702                 :             : 
    1703                 :          97 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
    1704                 :             : {
    1705                 :             :     assert(matcher);
    1706                 :             :     assert(prefix);
    1707                 :             : 
    1708         [ -  + ]:          97 :     DUMP(prefix, "struct bf_matcher at %p", matcher);
    1709                 :             : 
    1710                 :          97 :     bf_dump_prefix_push(prefix);
    1711                 :             : 
    1712         [ -  + ]:          97 :     DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
    1713         [ -  + ]:          97 :     DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
    1714   [ -  +  -  - ]:          97 :     DUMP(prefix, "negate: %s", matcher->negate ? "true" : "false");
    1715         [ -  + ]:          97 :     DUMP(prefix, "len: %ld", matcher->len);
    1716         [ -  + ]:          97 :     DUMP(bf_dump_prefix_last(prefix), "payload:");
    1717                 :          97 :     bf_dump_prefix_push(prefix);
    1718                 :          97 :     bf_dump_hex(prefix, matcher->payload,
    1719                 :          97 :                 matcher->len - sizeof(struct bf_matcher));
    1720                 :          97 :     bf_dump_prefix_pop(prefix);
    1721                 :             : 
    1722                 :          97 :     bf_dump_prefix_pop(prefix);
    1723                 :          97 : }
    1724                 :             : 
    1725                 :      104833 : enum bf_matcher_type bf_matcher_get_type(const struct bf_matcher *matcher)
    1726                 :             : {
    1727                 :             :     assert(matcher);
    1728                 :      104833 :     return matcher->type;
    1729                 :             : }
    1730                 :             : 
    1731                 :        5615 : enum bf_matcher_op bf_matcher_get_op(const struct bf_matcher *matcher)
    1732                 :             : {
    1733                 :             :     assert(matcher);
    1734                 :        5615 :     return matcher->op;
    1735                 :             : }
    1736                 :             : 
    1737                 :       11888 : const void *bf_matcher_payload(const struct bf_matcher *matcher)
    1738                 :             : {
    1739                 :             :     assert(matcher);
    1740                 :       11888 :     return matcher->payload;
    1741                 :             : }
    1742                 :             : 
    1743                 :         122 : size_t bf_matcher_payload_len(const struct bf_matcher *matcher)
    1744                 :             : {
    1745                 :             :     assert(matcher);
    1746                 :         122 :     return matcher->len - sizeof(*matcher);
    1747                 :             : }
    1748                 :             : 
    1749                 :           1 : size_t bf_matcher_len(const struct bf_matcher *matcher)
    1750                 :             : {
    1751                 :             :     assert(matcher);
    1752                 :           1 :     return matcher->len;
    1753                 :             : }
    1754                 :             : 
    1755                 :        3169 : bool bf_matcher_get_negate(const struct bf_matcher *matcher)
    1756                 :             : {
    1757                 :             :     assert(matcher);
    1758                 :        3169 :     return matcher->negate;
    1759                 :             : }
    1760                 :             : 
    1761                 :             : static const char *_bf_matcher_type_strs[] = {
    1762                 :             :     [BF_MATCHER_META_IFACE] = "meta.iface",
    1763                 :             :     [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
    1764                 :             :     [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
    1765                 :             :     [BF_MATCHER_META_PROBABILITY] = "meta.probability",
    1766                 :             :     [BF_MATCHER_META_SPORT] = "meta.sport",
    1767                 :             :     [BF_MATCHER_META_DPORT] = "meta.dport",
    1768                 :             :     [BF_MATCHER_META_MARK] = "meta.mark",
    1769                 :             :     [BF_MATCHER_META_FLOW_HASH] = "meta.flow_hash",
    1770                 :             :     [BF_MATCHER_META_FLOW_PROBABILITY] = "meta.flow_probability",
    1771                 :             :     [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
    1772                 :             :     [BF_MATCHER_IP4_SNET] = "ip4.snet",
    1773                 :             :     [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
    1774                 :             :     [BF_MATCHER_IP4_DNET] = "ip4.dnet",
    1775                 :             :     [BF_MATCHER_IP4_PROTO] = "ip4.proto",
    1776                 :             :     [BF_MATCHER_IP4_DSCP] = "ip4.dscp",
    1777                 :             :     [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
    1778                 :             :     [BF_MATCHER_IP6_SNET] = "ip6.snet",
    1779                 :             :     [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
    1780                 :             :     [BF_MATCHER_IP6_DNET] = "ip6.dnet",
    1781                 :             :     [BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
    1782                 :             :     [BF_MATCHER_IP6_DSCP] = "ip6.dscp",
    1783                 :             :     [BF_MATCHER_TCP_SPORT] = "tcp.sport",
    1784                 :             :     [BF_MATCHER_TCP_DPORT] = "tcp.dport",
    1785                 :             :     [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
    1786                 :             :     [BF_MATCHER_UDP_SPORT] = "udp.sport",
    1787                 :             :     [BF_MATCHER_UDP_DPORT] = "udp.dport",
    1788                 :             :     [BF_MATCHER_ICMP_TYPE] = "icmp.type",
    1789                 :             :     [BF_MATCHER_ICMP_CODE] = "icmp.code",
    1790                 :             :     [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
    1791                 :             :     [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
    1792                 :             :     [BF_MATCHER_SET] = "<set>",
    1793                 :             :     [BF_MATCHER_META_PID] = "meta.pid",
    1794                 :             : };
    1795                 :             : 
    1796                 :             : static_assert_enum_mapping(_bf_matcher_type_strs, _BF_MATCHER_TYPE_MAX);
    1797                 :             : 
    1798                 :        1320 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
    1799                 :             : {
    1800         [ +  - ]:        1320 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1801                 :             :         return "<invalid>";
    1802                 :             : 
    1803                 :        1320 :     return _bf_matcher_type_strs[type];
    1804                 :             : }
    1805                 :             : 
    1806                 :        3147 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
    1807                 :             : {
    1808                 :             :     assert(str);
    1809                 :             :     assert(type);
    1810                 :             : 
    1811         [ +  + ]:       51781 :     for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
    1812         [ +  + ]:       51775 :         if (bf_streq(_bf_matcher_type_strs[i], str)) {
    1813                 :        3141 :             *type = i;
    1814                 :        3141 :             return 0;
    1815                 :             :         }
    1816                 :             :     }
    1817                 :             : 
    1818                 :             :     return -EINVAL;
    1819                 :             : }
    1820                 :             : 
    1821                 :             : static const char *_bf_matcher_ops_strs[] = {
    1822                 :             :     [BF_MATCHER_EQ] = "eq",       [BF_MATCHER_ANY] = "any",
    1823                 :             :     [BF_MATCHER_ALL] = "all",     [BF_MATCHER_IN] = "in",
    1824                 :             :     [BF_MATCHER_RANGE] = "range",
    1825                 :             : };
    1826                 :             : 
    1827                 :             : static_assert_enum_mapping(_bf_matcher_ops_strs, _BF_MATCHER_OP_MAX);
    1828                 :             : 
    1829                 :        1103 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
    1830                 :             : {
    1831                 :             :     assert(0 <= op && op < _BF_MATCHER_OP_MAX);
    1832                 :             : 
    1833                 :        1103 :     return _bf_matcher_ops_strs[op];
    1834                 :             : }
    1835                 :             : 
    1836                 :        2027 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
    1837                 :             : {
    1838                 :             :     assert(str);
    1839                 :             :     assert(op);
    1840                 :             : 
    1841         [ +  + ]:        4148 :     for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
    1842         [ +  + ]:        4145 :         if (bf_streq(_bf_matcher_ops_strs[i], str)) {
    1843                 :        2024 :             *op = i;
    1844                 :        2024 :             return 0;
    1845                 :             :         }
    1846                 :             :     }
    1847                 :             : 
    1848                 :             :     return -EINVAL;
    1849                 :             : }
    1850                 :             : 
    1851                 :             : static const char *_bf_tcp_flags_strs[] = {
    1852                 :             :     [BF_TCP_FIN] = "fin", [BF_TCP_SYN] = "syn", [BF_TCP_RST] = "rst",
    1853                 :             :     [BF_TCP_PSH] = "psh", [BF_TCP_ACK] = "ack", [BF_TCP_URG] = "urg",
    1854                 :             :     [BF_TCP_ECE] = "ece", [BF_TCP_CWR] = "cwr",
    1855                 :             : };
    1856                 :             : static_assert_enum_mapping(_bf_tcp_flags_strs, _BF_TCP_MAX);
    1857                 :             : 
    1858                 :          10 : const char *bf_tcp_flag_to_str(enum bf_tcp_flag flag)
    1859                 :             : {
    1860                 :             :     assert(0 <= flag && flag < _BF_TCP_MAX);
    1861                 :             : 
    1862                 :          10 :     return _bf_tcp_flags_strs[flag];
    1863                 :             : }
    1864                 :             : 
    1865                 :         326 : int bf_tcp_flag_from_str(const char *str, enum bf_tcp_flag *flag)
    1866                 :             : {
    1867                 :             :     assert(str);
    1868                 :             :     assert(flag);
    1869                 :             : 
    1870         [ +  + ]:        1452 :     for (size_t i = 0; i < _BF_TCP_MAX; ++i) {
    1871         [ +  + ]:        1441 :         if (bf_streq_i(_bf_tcp_flags_strs[i], str)) {
    1872                 :         315 :             *flag = i;
    1873                 :         315 :             return 0;
    1874                 :             :         }
    1875                 :             :     }
    1876                 :             : 
    1877                 :             :     return -EINVAL;
    1878                 :             : }
    1879                 :             : 
    1880                 :           4 : const char *bf_ethertype_to_str(uint16_t ethertype)
    1881                 :             : {
    1882      [ +  +  + ]:           4 :     switch (ethertype) {
    1883                 :             :     case ETH_P_IP:
    1884                 :             :         return "ipv4";
    1885                 :           1 :     case ETH_P_IPV6:
    1886                 :           1 :         return "ipv6";
    1887                 :           1 :     default:
    1888                 :           1 :         return NULL;
    1889                 :             :     }
    1890                 :             : }
    1891                 :             : 
    1892                 :          93 : int bf_ethertype_from_str(const char *str, uint16_t *ethertype)
    1893                 :             : {
    1894                 :             :     assert(str);
    1895                 :             :     assert(ethertype);
    1896                 :             : 
    1897         [ +  + ]:          93 :     if (bf_streq_i(str, "ipv4")) {
    1898                 :          29 :         *ethertype = ETH_P_IP;
    1899                 :          29 :         return 0;
    1900                 :             :     }
    1901                 :             : 
    1902         [ +  + ]:          64 :     if (bf_streq_i(str, "ipv6")) {
    1903                 :          29 :         *ethertype = ETH_P_IPV6;
    1904                 :          29 :         return 0;
    1905                 :             :     }
    1906                 :             : 
    1907                 :             :     return -EINVAL;
    1908                 :             : }
    1909                 :             : 
    1910                 :             : static const char *_bf_ipproto_strs[UINT8_MAX + 1] = {
    1911                 :             :     [IPPROTO_HOPOPTS] = "hop",   [IPPROTO_ICMP] = "icmp",
    1912                 :             :     [IPPROTO_IGMP] = "igmp",     [IPPROTO_TCP] = "tcp",
    1913                 :             :     [IPPROTO_UDP] = "udp",       [IPPROTO_ROUTING] = "routing",
    1914                 :             :     [IPPROTO_FRAGMENT] = "frag", [IPPROTO_GRE] = "gre",
    1915                 :             :     [IPPROTO_AH] = "ah",         [IPPROTO_DSTOPTS] = "dst",
    1916                 :             :     [IPPROTO_ICMPV6] = "icmpv6", [IPPROTO_MH] = "mh",
    1917                 :             : };
    1918                 :             : 
    1919                 :           9 : const char *bf_ipproto_to_str(uint8_t ipproto)
    1920                 :             : {
    1921                 :           9 :     return _bf_ipproto_strs[ipproto];
    1922                 :             : }
    1923                 :             : 
    1924                 :         394 : int bf_ipproto_from_str(const char *str, uint8_t *ipproto)
    1925                 :             : {
    1926                 :             :     assert(str);
    1927                 :             :     assert(ipproto);
    1928                 :             : 
    1929         [ +  + ]:       30178 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1930         [ +  + ]:       30077 :         if (bf_streq_i(str, _bf_ipproto_strs[i])) {
    1931                 :         293 :             *ipproto = (uint8_t)i;
    1932                 :         293 :             return 0;
    1933                 :             :         }
    1934                 :             :     }
    1935                 :             : 
    1936                 :             :     return -EINVAL;
    1937                 :             : }
    1938                 :             : 
    1939                 :             : /* DSCP class name to codepoint mapping, based on the IANA DSCP
    1940                 :             :  * registry (https://www.iana.org/assignments/dscp-registry).
    1941                 :             :  * BE is an alias for CS0. */
    1942                 :             : static const struct
    1943                 :             : {
    1944                 :             :     const char *name;
    1945                 :             :     uint8_t dscp;
    1946                 :             : } _bf_dscp_classes[] = {
    1947                 :             :     {"cs0", 0},   {"cs1", 8},          {"cs2", 16},  {"cs3", 24},  {"cs4", 32},
    1948                 :             :     {"cs5", 40},  {"cs6", 48},         {"cs7", 56},  {"af11", 10}, {"af12", 12},
    1949                 :             :     {"af13", 14}, {"af21", 18},        {"af22", 20}, {"af23", 22}, {"af31", 26},
    1950                 :             :     {"af32", 28}, {"af33", 30},        {"af41", 34}, {"af42", 36}, {"af43", 38},
    1951                 :             :     {"ef", 46},   {"voice-admit", 44}, {"le", 1},    {"nqb", 45},  {"be", 0},
    1952                 :             : };
    1953                 :             : 
    1954                 :           5 : const char *bf_dscp_class_to_str(uint8_t dscp)
    1955                 :             : {
    1956         [ +  + ]:          79 :     for (size_t i = 0; i < ARRAY_SIZE(_bf_dscp_classes); ++i) {
    1957         [ +  + ]:          77 :         if (_bf_dscp_classes[i].dscp == dscp)
    1958                 :           3 :             return _bf_dscp_classes[i].name;
    1959                 :             :     }
    1960                 :             : 
    1961                 :             :     return NULL;
    1962                 :             : }
    1963                 :             : 
    1964                 :          95 : int bf_dscp_class_from_str(const char *str, uint8_t *dscp)
    1965                 :             : {
    1966                 :             :     assert(str);
    1967                 :             :     assert(dscp);
    1968                 :             : 
    1969         [ +  + ]:        2321 :     for (size_t i = 0; i < ARRAY_SIZE(_bf_dscp_classes); ++i) {
    1970         [ +  + ]:        2245 :         if (bf_streq_i(str, _bf_dscp_classes[i].name)) {
    1971                 :          19 :             *dscp = _bf_dscp_classes[i].dscp;
    1972                 :          19 :             return 0;
    1973                 :             :         }
    1974                 :             :     }
    1975                 :             : 
    1976                 :             :     return -EINVAL;
    1977                 :             : }
    1978                 :             : 
    1979                 :             : #define ICMP_ROUTERADVERT 9
    1980                 :             : #define ICMP_ROUTERSOLICIT 10
    1981                 :             : 
    1982                 :             : static const char *_bf_icmp_type_strs[UINT8_MAX + 1] = {
    1983                 :             :     [ICMP_ECHOREPLY] = "echo-reply",
    1984                 :             :     [ICMP_DEST_UNREACH] = "destination-unreachable",
    1985                 :             :     [ICMP_SOURCE_QUENCH] = "source-quench",
    1986                 :             :     [ICMP_REDIRECT] = "redirect",
    1987                 :             :     [ICMP_ECHO] = "echo-request",
    1988                 :             :     [ICMP_ROUTERADVERT] = "router-advertisement",
    1989                 :             :     [ICMP_ROUTERSOLICIT] = "router-solicitation",
    1990                 :             :     [ICMP_TIME_EXCEEDED] = "time-exceeded",
    1991                 :             :     [ICMP_PARAMETERPROB] = "parameter-problem",
    1992                 :             :     [ICMP_TIMESTAMP] = "timestamp-request",
    1993                 :             :     [ICMP_TIMESTAMPREPLY] = "timestamp-reply",
    1994                 :             :     [ICMP_INFO_REQUEST] = "info-request",
    1995                 :             :     [ICMP_INFO_REPLY] = "info-reply",
    1996                 :             :     [ICMP_ADDRESS] = "address-mask-request",
    1997                 :             :     [ICMP_ADDRESSREPLY] = "address-mask-reply",
    1998                 :             : };
    1999                 :             : 
    2000                 :           4 : const char *bf_icmp_type_to_str(uint8_t type)
    2001                 :             : {
    2002                 :           4 :     return _bf_icmp_type_strs[type];
    2003                 :             : }
    2004                 :             : 
    2005                 :          91 : int bf_icmp_type_from_str(const char *str, uint8_t *type)
    2006                 :             : {
    2007                 :             :     assert(str);
    2008                 :             :     assert(type);
    2009                 :             : 
    2010         [ +  + ]:       14765 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    2011         [ +  + ]:       14708 :         if (bf_streq_i(str, _bf_icmp_type_strs[i])) {
    2012                 :          34 :             *type = (uint8_t)i;
    2013                 :          34 :             return 0;
    2014                 :             :         }
    2015                 :             :     }
    2016                 :             : 
    2017                 :             :     return -EINVAL;
    2018                 :             : }
    2019                 :             : 
    2020                 :             : #define ICMPV6_ND_ROUTERSOLICIT 133
    2021                 :             : #define ICMPV6_ND_ROUTERADVERT 134
    2022                 :             : #define ICMPV6_ND_NEIGHSOLICIT 135
    2023                 :             : #define ICMPV6_ND_NEIGHADVERT 136
    2024                 :             : 
    2025                 :             : static const char *_bf_icmpv6_type_strs[UINT8_MAX + 1] = {
    2026                 :             :     [ICMPV6_DEST_UNREACH] = "destination-unreachable",
    2027                 :             :     [ICMPV6_PKT_TOOBIG] = "packet-too-big",
    2028                 :             :     [ICMPV6_TIME_EXCEED] = "time-exceeded",
    2029                 :             :     [ICMPV6_PARAMPROB] = "parameter-problem",
    2030                 :             :     [ICMPV6_ECHO_REQUEST] = "echo-request",
    2031                 :             :     [ICMPV6_ECHO_REPLY] = "echo-reply",
    2032                 :             :     [ICMPV6_MGM_QUERY] = "mld-listener-query",
    2033                 :             :     [ICMPV6_MGM_REPORT] = "mld-listener-report",
    2034                 :             :     [ICMPV6_MGM_REDUCTION] = "mld-listener-reduction",
    2035                 :             :     [ICMPV6_ND_ROUTERSOLICIT] = "nd-router-solicit",
    2036                 :             :     [ICMPV6_ND_ROUTERADVERT] = "nd-router-advert",
    2037                 :             :     [ICMPV6_ND_NEIGHSOLICIT] = "nd-neighbor-solicit",
    2038                 :             :     [ICMPV6_ND_NEIGHADVERT] = "nd-neighbor-advert",
    2039                 :             :     [ICMPV6_MLD2_REPORT] = "mld2-listener-report",
    2040                 :             : };
    2041                 :             : 
    2042                 :           4 : const char *bf_icmpv6_type_to_str(uint8_t type)
    2043                 :             : {
    2044                 :           4 :     return _bf_icmpv6_type_strs[type];
    2045                 :             : }
    2046                 :             : 
    2047                 :          99 : int bf_icmpv6_type_from_str(const char *str, uint8_t *type)
    2048                 :             : {
    2049                 :             :     assert(str);
    2050                 :             :     assert(type);
    2051                 :             : 
    2052         [ +  + ]:       20230 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    2053         [ +  + ]:       20171 :         if (bf_streq_i(str, _bf_icmpv6_type_strs[i])) {
    2054                 :          40 :             *type = (uint8_t)i;
    2055                 :          40 :             return 0;
    2056                 :             :         }
    2057                 :             :     }
    2058                 :             : 
    2059                 :             :     return -EINVAL;
    2060                 :             : }
        

Generated by: LCOV version 2.0-1