LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 95.3 % 425 405
Test Date: 2026-02-28 14:57:49 Functions: 96.9 % 65 63
Branches: 79.8 % 321 256

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

Generated by: LCOV version 2.0-1