LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 94.6 % 407 385
Test Date: 2026-05-09 09:49:18 Functions: 97.0 % 67 65
Branches: 75.1 % 313 235

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

Generated by: LCOV version 2.0-1