LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 95.2 % 416 396
Test Date: 2026-03-19 16:00:55 Functions: 96.8 % 63 61
Branches: 79.2 % 313 248

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

Generated by: LCOV version 2.0-1