LCOV - code coverage report
Current view: top level - lib/graph - graph_feature_arc.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 559 758 73.7 %
Date: 2025-08-01 17:49:26 Functions: 31 34 91.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 404 640 63.1 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(C) 2025 Marvell International Ltd.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <rte_graph_feature_arc_worker.h>
       6                 :            : #include <rte_malloc.h>
       7                 :            : #include <rte_string_fns.h>
       8                 :            : #include <eal_export.h>
       9                 :            : #include "graph_private.h"
      10                 :            : 
      11                 :            : #define GRAPH_FEATURE_MAX_NUM_PER_ARC  (64)
      12                 :            : 
      13                 :            : #define connect_graph_nodes(node1, node2, edge, arc_name) \
      14                 :            :         __connect_graph_nodes(node1, node2, edge, arc_name, __LINE__)
      15                 :            : 
      16                 :            : #define FEATURE_ARC_MEMZONE_NAME "__rte_feature_arc_main_mz"
      17                 :            : 
      18                 :            : #define NUM_EXTRA_FEATURE_DATA   (2)
      19                 :            : 
      20                 :            : #define graph_uint_cast(f)              ((unsigned int)(f))
      21                 :            : 
      22                 :            : #define fdata_fix_get(arc, feat, index) \
      23                 :            :                         RTE_GRAPH_FEATURE_TO_FEATURE_DATA(arc, feat, index)
      24                 :            : 
      25                 :            : #define feat_dbg graph_dbg
      26                 :            : 
      27                 :            : #define FEAT_COND_ERR(cond, ...)                                           \
      28                 :            :         do {                                                               \
      29                 :            :                 if (cond)                                                  \
      30                 :            :                         graph_err(__VA_ARGS__);                            \
      31                 :            :         } while (0)
      32                 :            : 
      33                 :            : #define FEAT_ERR(fn, ln, ...)                                              \
      34                 :            :                 GRAPH_LOG2(ERR, fn, ln, __VA_ARGS__)
      35                 :            : 
      36                 :            : #define FEAT_ERR_JMP(_err, fn, ln, ...)                                    \
      37                 :            :         do {                                                               \
      38                 :            :                 FEAT_ERR(fn, ln, __VA_ARGS__);                             \
      39                 :            :                 rte_errno = _err;                                          \
      40                 :            :         } while (0)
      41                 :            : 
      42                 :            : #define COND_ERR_JMP(_err, cond, fn, ln, ...)                              \
      43                 :            :         do {                                                               \
      44                 :            :                 if (cond)                                                  \
      45                 :            :                         FEAT_ERR(fn, ln, __VA_ARGS__);                     \
      46                 :            :                 rte_errno = _err;                                          \
      47                 :            :         } while (0)
      48                 :            : 
      49                 :            : 
      50                 :            : static struct rte_mbuf_dynfield rte_graph_feature_arc_mbuf_desc = {
      51                 :            :         .name = RTE_GRAPH_FEATURE_ARC_DYNFIELD_NAME,
      52                 :            :         .size = sizeof(struct rte_graph_feature_arc_mbuf_dynfields),
      53                 :            :         .align = alignof(struct rte_graph_feature_arc_mbuf_dynfields),
      54                 :            : };
      55                 :            : 
      56                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(__rte_graph_feature_arc_main, 25.07)
      57                 :            : rte_graph_feature_arc_main_t *__rte_graph_feature_arc_main;
      58                 :            : 
      59                 :            : /* global feature arc list */
      60                 :            : static STAILQ_HEAD(, rte_graph_feature_arc_register) feature_arc_list =
      61                 :            :                                         STAILQ_HEAD_INITIALIZER(feature_arc_list);
      62                 :            : 
      63                 :            : /* global feature arc list */
      64                 :            : static STAILQ_HEAD(, rte_graph_feature_register) feature_list =
      65                 :            :                                         STAILQ_HEAD_INITIALIZER(feature_list);
      66                 :            : 
      67                 :            :  /*
      68                 :            :   * feature data index is not fixed for given [feature, index], although it can
      69                 :            :   * be, which is calculated as follows (fdata_fix_get())
      70                 :            :   *
      71                 :            :   * fdata = (arc->max_features * feature ) + index;
      72                 :            :   *
      73                 :            :   * But feature data index should not be fixed for any index. i.e
      74                 :            :   * on any index, feature data can be placed. A slow path array is
      75                 :            :   * maintained and within a feature range [start, end] it is checked where
      76                 :            :   * feature_data_index is already placed.
      77                 :            :   *
      78                 :            :   * If is_release == false. feature_data_index is searched in a feature range.
      79                 :            :   * If found, index is returned. If not found, then reserve and return.
      80                 :            :   *
      81                 :            :   * If is_release == true, then feature_data_index is released for further
      82                 :            :   * usage
      83                 :            :   */
      84                 :            : static rte_graph_feature_data_t
      85                 :       3057 : fdata_dyn_reserve_or_rel(struct rte_graph_feature_arc *arc, rte_graph_feature_t f,
      86                 :            :                          uint32_t index, bool is_release,
      87                 :            :                          bool fdata_provided, rte_graph_feature_data_t fd)
      88                 :            : {
      89                 :            :         rte_graph_feature_data_t start, end, fdata;
      90                 :            :         rte_graph_feature_t next_feat;
      91                 :            : 
      92         [ +  + ]:       3057 :         if (fdata_provided)
      93                 :            :                 fdata = fd;
      94                 :            :         else
      95                 :       2513 :                 fdata = fdata_fix_get(arc, f, index);
      96                 :            : 
      97                 :       3057 :         next_feat = f + 1;
      98                 :            :         /* Find in a given feature range, feature data is stored or not */
      99                 :       3057 :         for (start = fdata_fix_get(arc, f, 0),
     100                 :       3057 :              end = fdata_fix_get(arc, next_feat, 0);
     101         [ +  + ]:     491499 :              start < end;
     102                 :     488442 :              start++) {
     103         [ +  + ]:     490208 :                 if (arc->feature_data_by_index[start] == fdata) {
     104         [ +  + ]:       1766 :                         if (is_release)
     105                 :        544 :                                 arc->feature_data_by_index[start] = RTE_GRAPH_FEATURE_DATA_INVALID;
     106                 :            : 
     107                 :       1766 :                         return start;
     108                 :            :                 }
     109                 :            :         }
     110                 :            : 
     111         [ +  + ]:       1291 :         if (is_release)
     112                 :            :                 return RTE_GRAPH_FEATURE_DATA_INVALID;
     113                 :            : 
     114                 :            :         /* If not found, then reserve valid one */
     115                 :            :         for (start = fdata_fix_get(arc, f, 0),
     116                 :            :              end = fdata_fix_get(arc, next_feat, 0);
     117         [ +  - ]:     105372 :              start < end;
     118                 :     104353 :              start++) {
     119         [ +  + ]:     105372 :                 if (arc->feature_data_by_index[start] == RTE_GRAPH_FEATURE_DATA_INVALID) {
     120                 :       1019 :                         arc->feature_data_by_index[start] = fdata;
     121                 :       1019 :                         return start;
     122                 :            :                 }
     123                 :            :         }
     124                 :            : 
     125                 :            :         return RTE_GRAPH_FEATURE_DATA_INVALID;
     126                 :            : }
     127                 :            : 
     128                 :            : static rte_graph_feature_data_t
     129                 :            : fdata_reserve(struct rte_graph_feature_arc *arc,
     130                 :            :               rte_graph_feature_t feature,
     131                 :            :               uint32_t index)
     132                 :            : {
     133                 :        272 :         return fdata_dyn_reserve_or_rel(arc, feature + 1, index, false, false, 0);
     134                 :            : }
     135                 :            : 
     136                 :            : static rte_graph_feature_data_t
     137                 :            : fdata_release(struct rte_graph_feature_arc *arc,
     138                 :            :               rte_graph_feature_t feature,
     139                 :            :               uint32_t index)
     140                 :            : {
     141                 :        272 :         return fdata_dyn_reserve_or_rel(arc, feature + 1, index, true, false, 0);
     142                 :            : }
     143                 :            : 
     144                 :            : static rte_graph_feature_data_t
     145                 :            : first_fdata_reserve(struct rte_graph_feature_arc *arc,
     146                 :            :                     uint32_t index)
     147                 :            : {
     148                 :        475 :         return fdata_dyn_reserve_or_rel(arc, 0, index, false, false, 0);
     149                 :            : }
     150                 :            : 
     151                 :            : static rte_graph_feature_data_t
     152                 :            : first_fdata_release(struct rte_graph_feature_arc *arc,
     153                 :            :                     uint32_t index)
     154                 :            : {
     155                 :        272 :         return fdata_dyn_reserve_or_rel(arc, 0, index, true, false, 0);
     156                 :            : }
     157                 :            : 
     158                 :            : static rte_graph_feature_data_t
     159                 :        272 : extra_fdata_reserve(struct rte_graph_feature_arc *arc,
     160                 :            :                     rte_graph_feature_t feature,
     161                 :            :                     uint32_t index)
     162                 :            : {
     163                 :            :         rte_graph_feature_data_t fdata, fdata2;
     164                 :            :         rte_graph_feature_t f;
     165                 :            : 
     166                 :        272 :         f = arc->num_added_features + NUM_EXTRA_FEATURE_DATA - 1;
     167                 :            : 
     168                 :        272 :         fdata = fdata_dyn_reserve_or_rel(arc, f, index,
     169                 :        272 :                                          false, true, fdata_fix_get(arc, feature + 1, index));
     170                 :            : 
     171                 :            :         /* we do not have enough space in as
     172                 :            :          * extra fdata accommodates indexes for all features
     173                 :            :          * Needed (feature * index) space but has only (index) number of space.
     174                 :            :          * So dynamic allocation can fail.  When fail use static allocation
     175                 :            :          */
     176         [ -  + ]:        272 :         if (fdata == RTE_GRAPH_FEATURE_DATA_INVALID) {
     177                 :          0 :                 fdata = fdata_fix_get(arc, feature + 1, index);
     178                 :          0 :                 fdata2 = fdata_fix_get(arc, f, index);
     179                 :          0 :                 arc->feature_data_by_index[fdata2] = fdata;
     180                 :            :         }
     181                 :        272 :         return fdata;
     182                 :            : }
     183                 :            : 
     184                 :            : static rte_graph_feature_data_t
     185                 :        272 : extra_fdata_release(struct rte_graph_feature_arc *arc,
     186                 :            :                     rte_graph_feature_t feature,
     187                 :            :                     uint32_t index)
     188                 :            : {
     189                 :            :         rte_graph_feature_t f;
     190                 :            : 
     191                 :        272 :         f = arc->num_added_features + NUM_EXTRA_FEATURE_DATA - 1;
     192                 :        544 :         return fdata_dyn_reserve_or_rel(arc, f, index,
     193                 :        272 :                                         true, true, fdata_fix_get(arc, feature + 1, index));
     194                 :            : }
     195                 :            : 
     196                 :            : /* feature registration validate */
     197                 :            : static int
     198                 :       1160 : feature_registration_validate(struct rte_graph_feature_register *feat_entry,
     199                 :            :                               const char *caller_name, int lineno,
     200                 :            :                               int check_node_reg_id, /* check feature_node->id */
     201                 :            :                               int check_feat_reg_id, /* check feature->feature_node_id */
     202                 :            :                               bool verbose /* print error */)
     203                 :            : {
     204         [ -  + ]:       1160 :         if (!feat_entry) {
     205         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno, "NULL feature reg");
     206                 :          0 :                 return -1;
     207                 :            :         }
     208                 :            : 
     209         [ -  + ]:       1160 :         if (!feat_entry->feature_name) {
     210         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     211                 :            :                              "%p: NULL feature name", feat_entry);
     212                 :          0 :                 return -1;
     213                 :            :         }
     214                 :            : 
     215         [ -  + ]:       1160 :         if (!feat_entry->arc_name) {
     216         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     217                 :            :                              "feature-\"%s\": No associated arc provided",
     218                 :            :                              feat_entry->feature_name);
     219                 :          0 :                 return -1;
     220                 :            :         }
     221                 :            : 
     222         [ +  + ]:       1160 :         if (!feat_entry->feature_process_fn) {
     223         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     224                 :            :                              "feature-\"%s\": No process function provided",
     225                 :            :                              feat_entry->feature_name);
     226                 :         13 :                 return -1;
     227                 :            :         }
     228                 :            : 
     229         [ +  + ]:       1147 :         if (!feat_entry->feature_node) {
     230         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     231                 :            :                              "feature-\"%s\": No feature_node provided",
     232                 :            :                              feat_entry->feature_name);
     233                 :         13 :                 return -1;
     234                 :            :         }
     235                 :            : 
     236   [ +  +  -  + ]:       1134 :         if (check_node_reg_id && (feat_entry->feature_node->id == RTE_NODE_ID_INVALID)) {
     237         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     238                 :            :                              "feature-\"%s\": feature_node with invalid node-id found",
     239                 :            :                              feat_entry->feature_name);
     240                 :          0 :                 return -1;
     241                 :            :         }
     242                 :            : 
     243   [ +  +  -  + ]:       1134 :         if (check_feat_reg_id && (feat_entry->feature_node_id == RTE_NODE_ID_INVALID)) {
     244         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     245                 :            :                              "feature-\"%s\": feature_node_id found invalid",
     246                 :            :                              feat_entry->feature_name);
     247                 :          0 :                 return -1;
     248                 :            :         }
     249         [ +  + ]:       1134 :         if (check_feat_reg_id && feat_entry->feature_node) {
     250         [ -  + ]:         28 :                 if (feat_entry->feature_node_id != feat_entry->feature_node->id) {
     251         [ #  # ]:          0 :                         COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     252                 :            :                                      "feature-\"%s\": feature_node_id(%u) not corresponding to %s->id(%u)",
     253                 :            :                                      feat_entry->feature_name, feat_entry->feature_node_id,
     254                 :            :                                      feat_entry->feature_node->name, feat_entry->feature_node->id);
     255                 :          0 :                         return -1;
     256                 :            :                 }
     257                 :            :         }
     258                 :            : 
     259                 :            :         return 0;
     260                 :            : }
     261                 :            : 
     262                 :            : /* validate arc registration */
     263                 :            : static int
     264                 :        150 : arc_registration_validate(struct rte_graph_feature_arc_register *reg,
     265                 :            :                           const char *caller_name, int lineno,
     266                 :            :                           bool verbose)
     267                 :            : {
     268                 :            : 
     269         [ -  + ]:        150 :         if (reg == NULL) {
     270         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     271                 :            :                              "arc registration cannot be NULL");
     272                 :          0 :                 return -1;
     273                 :            :         }
     274                 :            : 
     275         [ -  + ]:        150 :         if (!reg->arc_name) {
     276         [ #  # ]:          0 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     277                 :            :                              "feature_arc name cannot be NULL");
     278                 :          0 :                 return -1;
     279                 :            :         }
     280                 :            : 
     281         [ -  + ]:        150 :         if (reg->max_features > GRAPH_FEATURE_MAX_NUM_PER_ARC) {
     282         [ #  # ]:          0 :                 COND_ERR_JMP(EAGAIN, verbose, caller_name, lineno,
     283                 :            :                              "arc-\"%s\", invalid number of features (found: %u, exp: %u)",
     284                 :            :                              reg->arc_name, reg->max_features, GRAPH_FEATURE_MAX_NUM_PER_ARC);
     285                 :          0 :                 return -1;
     286                 :            :         }
     287                 :            : 
     288         [ +  + ]:        150 :         if (!reg->max_indexes) {
     289         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     290                 :            :                              "arc-\"%s\": Zero max_indexes found",
     291                 :            :                              reg->arc_name);
     292                 :         13 :                 return -1;
     293                 :            :         }
     294                 :            : 
     295         [ +  + ]:        137 :         if (!reg->start_node) {
     296         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     297                 :            :                              "arc-\"%s\": start node cannot be NULL",
     298                 :            :                              reg->arc_name);
     299                 :         13 :                 return -1;
     300                 :            :         }
     301                 :            : 
     302         [ +  + ]:        124 :         if (!reg->start_node_feature_process_fn) {
     303         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     304                 :            :                              "arc-\"%s\": start node feature_process_fn() cannot be NULL",
     305                 :            :                              reg->arc_name);
     306                 :         13 :                 return -1;
     307                 :            :         }
     308                 :            : 
     309         [ +  + ]:        111 :         if (!reg->end_feature) {
     310         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     311                 :            :                              "arc-\"%s\": end_feature cannot be NULL",
     312                 :            :                              reg->arc_name);
     313                 :         13 :                 return -1;
     314                 :            :         }
     315                 :            : 
     316         [ +  + ]:         98 :         if (feature_registration_validate(reg->end_feature, caller_name, lineno, 1, 0, verbose))
     317                 :            :                 return -1;
     318                 :            : 
     319         [ +  + ]:         72 :         if (strncmp(reg->arc_name, reg->end_feature->arc_name,
     320                 :            :                     RTE_GRAPH_FEATURE_ARC_NAMELEN)) {
     321         [ +  + ]:         13 :                 COND_ERR_JMP(EINVAL, verbose, caller_name, lineno,
     322                 :            :                              "arc-\"%s\"/feature-\"%s\": mismatch in arc_name in end_feature",
     323                 :            :                              reg->arc_name, reg->end_feature->feature_name);
     324                 :         13 :                 return -1;
     325                 :            :         }
     326                 :            : 
     327                 :            :         return 0;
     328                 :            : }
     329                 :            : 
     330                 :            : /* lookup arc registration by name */
     331                 :            : static int arc_registration_num(void)
     332                 :            : {
     333                 :            :         struct rte_graph_feature_arc_register *entry = NULL;
     334                 :            :         int num = 0;
     335                 :            : 
     336         [ +  + ]:         20 :         STAILQ_FOREACH(entry, &feature_arc_list, next_arc)
     337                 :         18 :                 num++;
     338                 :            : 
     339                 :            :         return num;
     340                 :            : }
     341                 :            : 
     342                 :            : 
     343                 :            : /* lookup arc registration by name */
     344                 :         34 : static int arc_registration_lookup(const char *arc_name,
     345                 :            :                                    struct rte_graph_feature_arc_register **arc_entry,
     346                 :            :                                    bool verbose /* print error */)
     347                 :            : {
     348                 :            :         struct rte_graph_feature_arc_register *entry = NULL;
     349                 :            : 
     350         [ +  + ]:        128 :         STAILQ_FOREACH(entry, &feature_arc_list, next_arc) {
     351         [ +  + ]:        122 :                 if (arc_registration_validate(entry, __func__, __LINE__, verbose) < 0)
     352                 :         77 :                         continue;
     353                 :            : 
     354         [ +  + ]:         45 :                 if (!strncmp(entry->arc_name, arc_name, RTE_GRAPH_FEATURE_ARC_NAMELEN)) {
     355         [ +  + ]:         28 :                         if (arc_entry)
     356                 :          6 :                                 *arc_entry = entry;
     357                 :         28 :                         return 1;
     358                 :            :                 }
     359                 :            :         }
     360                 :            : 
     361                 :            :         return 0;
     362                 :            : }
     363                 :            : 
     364                 :            : 
     365                 :            : /* Number of features registered for an ARC
     366                 :            :  *
     367                 :            :  * i.e number of RTE_GRAPH_FEATURE_REGISTER() for an arc
     368                 :            :  */
     369                 :            : static int
     370                 :          2 : arc_registered_features_num(const char *arc_name, uint16_t *num_features)
     371                 :            : {
     372                 :          2 :         struct rte_graph_feature_arc_register *arc_reg = NULL;
     373                 :            :         struct rte_graph_feature_register *feat_entry = NULL;
     374                 :            :         uint16_t num = 0;
     375                 :            : 
     376                 :            :         /* Check if arc is registered with end_feature */
     377         [ +  - ]:          2 :         if (!arc_registration_lookup(arc_name, &arc_reg, false))
     378                 :            :                 return -1;
     379                 :            : 
     380         [ +  - ]:          2 :         if (arc_reg->end_feature)
     381                 :            :                 num++;
     382                 :            : 
     383                 :            :         /* Calculate features other than end_feature added in arc */
     384         [ +  + ]:         10 :         STAILQ_FOREACH(feat_entry, &feature_list, next_feature) {
     385         [ -  + ]:          8 :                 if (feature_registration_validate(feat_entry, __func__, __LINE__, 1, 0, false) < 0)
     386                 :          0 :                         continue;
     387                 :            : 
     388         [ +  + ]:          8 :                 if (!strncmp(feat_entry->arc_name, arc_name, strlen(feat_entry->arc_name)))
     389                 :          3 :                         num++;
     390                 :            :         }
     391                 :            : 
     392         [ +  - ]:          2 :         if (num_features)
     393                 :          2 :                 *num_features = num;
     394                 :            : 
     395                 :            :         return 0;
     396                 :            : }
     397                 :            : 
     398                 :            : static int
     399                 :          4 : arc_max_index_get(const char *arc_name, uint16_t *max_indexes)
     400                 :            : {
     401                 :          4 :         struct rte_graph_feature_arc_register *arc_reg = NULL;
     402                 :            :         struct rte_graph_feature_register *feat_entry = NULL;
     403                 :            :         uint16_t index;
     404                 :            : 
     405         [ +  - ]:          4 :         if (!max_indexes)
     406                 :            :                 return -1;
     407                 :            : 
     408                 :            :         /* Check if arc is registered with end_feature */
     409         [ +  - ]:          4 :         if (!arc_registration_lookup(arc_name, &arc_reg, false))
     410                 :            :                 return -1;
     411                 :            : 
     412                 :          4 :         index = *max_indexes;
     413                 :            : 
     414                 :            :         /* Call features override_index_cb(), if set */
     415         [ +  + ]:         20 :         STAILQ_FOREACH(feat_entry, &feature_list, next_feature) {
     416         [ +  + ]:         16 :                 if (!feat_entry->override_index_cb)
     417                 :          8 :                         continue;
     418                 :            : 
     419         [ -  + ]:          8 :                 if (feature_registration_validate(feat_entry, __func__, __LINE__, 1, 0, false) < 0)
     420                 :          0 :                         continue;
     421                 :            : 
     422                 :          8 :                 index = RTE_MAX(index, feat_entry->override_index_cb());
     423                 :            :         }
     424                 :            : 
     425                 :          4 :         *max_indexes = index;
     426                 :            : 
     427                 :          4 :         return 0;
     428                 :            : }
     429                 :            : 
     430                 :            : /* calculate arc size to be allocated */
     431                 :            : static int
     432                 :            : feature_arc_reg_calc_size(struct rte_graph_feature_arc_register *reg, size_t *sz,
     433                 :            :                           uint16_t *feat_off, uint16_t *fdata_off, uint32_t *fsz,
     434                 :            :                           uint16_t *num_index)
     435                 :            : {
     436                 :            :         size_t ff_size = 0, fdata_size = 0;
     437                 :            : 
     438                 :            :         /* first feature array per index */
     439                 :          9 :         ff_size = RTE_ALIGN_CEIL(sizeof(rte_graph_feature_data_t) * reg->max_indexes,
     440                 :            :                                  RTE_CACHE_LINE_SIZE);
     441                 :            : 
     442                 :            : 
     443                 :            :         /* fdata size per feature */
     444                 :          9 :         *fsz = (uint32_t)RTE_ALIGN_CEIL(sizeof(struct rte_graph_feature_data) * reg->max_indexes,
     445                 :            :                                         RTE_CACHE_LINE_SIZE);
     446                 :            : 
     447                 :          9 :         *num_index = (*fsz)/sizeof(struct rte_graph_feature_data);
     448                 :            : 
     449                 :            :         /* Allocate feature_data extra by 2.
     450                 :            :          * 0th index is used for first feature data from start_node
     451                 :            :          * Last feature data is used for extra_fdata for end_feature
     452                 :            :          */
     453                 :          9 :         fdata_size = (*fsz) * (reg->max_features + NUM_EXTRA_FEATURE_DATA);
     454                 :            : 
     455                 :            :         if (sz)
     456                 :          9 :                 *sz = fdata_size + ff_size + sizeof(struct rte_graph_feature_arc);
     457                 :            :         if (feat_off)
     458                 :            :                 *feat_off = sizeof(struct rte_graph_feature_arc);
     459                 :            :         if (fdata_off)
     460                 :          9 :                 *fdata_off = ff_size + sizeof(struct rte_graph_feature_arc);
     461                 :            : 
     462                 :            :         return 0;
     463                 :            : }
     464                 :            : 
     465                 :            : static rte_graph_feature_data_t *
     466                 :            : graph_first_feature_data_ptr_get(struct rte_graph_feature_arc *arc,
     467                 :            :                                  uint32_t index)
     468                 :            : {
     469                 :       1579 :         return (rte_graph_feature_data_t *)((uint8_t *)arc + arc->fp_first_feature_offset +
     470                 :       1579 :                                             (sizeof(rte_graph_feature_data_t) * index));
     471                 :            : }
     472                 :            : 
     473                 :            : static int
     474                 :          9 : feature_arc_data_reset(struct rte_graph_feature_arc *arc)
     475                 :            : {
     476                 :            :         rte_graph_feature_data_t first_fdata;
     477                 :            :         struct rte_graph_feature_data *fdata;
     478                 :            :         rte_graph_feature_data_t *f = NULL;
     479                 :            :         rte_graph_feature_t iter;
     480                 :            :         uint16_t index;
     481                 :            : 
     482                 :          9 :         arc->runtime_enabled_features = 0;
     483                 :            : 
     484         [ +  + ]:       1113 :         for (index = 0; index < arc->max_indexes; index++) {
     485                 :            :                 f = graph_first_feature_data_ptr_get(arc, index);
     486                 :       1104 :                 *f = RTE_GRAPH_FEATURE_DATA_INVALID;
     487                 :            :         }
     488                 :            : 
     489         [ +  + ]:         54 :         for (iter = 0; iter < arc->max_features + NUM_EXTRA_FEATURE_DATA; iter++) {
     490                 :         45 :                 first_fdata = fdata_fix_get(arc, iter, 0);
     491         [ +  + ]:       5085 :                 for (index = 0; index < arc->max_indexes; index++) {
     492         [ +  - ]:       5040 :                         fdata = rte_graph_feature_data_get(arc, first_fdata + index);
     493                 :       5040 :                         fdata->next_feature_data = RTE_GRAPH_FEATURE_DATA_INVALID;
     494                 :       5040 :                         fdata->app_cookie = UINT16_MAX;
     495                 :       5040 :                         fdata->next_edge = RTE_EDGE_ID_INVALID;
     496                 :            :                 }
     497                 :            :         }
     498                 :          9 :         return 0;
     499                 :            : }
     500                 :            : 
     501                 :            : /*
     502                 :            :  * lookup feature name and get control path node_list as well as feature index
     503                 :            :  * at which it is inserted
     504                 :            :  */
     505                 :            : static int
     506                 :       1100 : nodeinfo_lkup_by_name(struct rte_graph_feature_arc *arc, const char *feat_name,
     507                 :            :                       struct rte_graph_feature_node_list **ffinfo, uint32_t *slot)
     508                 :            : {
     509                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
     510                 :            :         uint32_t fi = 0;
     511                 :            : 
     512         [ +  - ]:       1100 :         if (!feat_name)
     513                 :            :                 return -1;
     514                 :            : 
     515         [ +  + ]:       1100 :         if (slot)
     516                 :       1090 :                 *slot = UINT32_MAX;
     517                 :            : 
     518         [ +  + ]:       2702 :         STAILQ_FOREACH(finfo, &arc->all_features, next_feature) {
     519         [ +  + ]:       2701 :                 if (!strncmp(finfo->feature_name, feat_name, strlen(finfo->feature_name))) {
     520         [ +  - ]:       1099 :                         if (ffinfo)
     521                 :       1099 :                                 *ffinfo = finfo;
     522         [ +  + ]:       1099 :                         if (slot)
     523                 :       1089 :                                 *slot = fi;
     524                 :       1099 :                         return 0;
     525                 :            :                 }
     526                 :       1602 :                 fi++;
     527                 :            :         }
     528                 :            :         return -1;
     529                 :            : }
     530                 :            : 
     531                 :            : /* Lookup used only during rte_graph_feature_add() */
     532                 :            : static int
     533                 :         18 : nodeinfo_add_lookup(struct rte_graph_feature_arc *arc, const char *feat_node_name,
     534                 :            :                     struct rte_graph_feature_node_list **ffinfo, uint32_t *slot)
     535                 :            : {
     536                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
     537                 :            :         uint32_t fi = 0;
     538                 :            : 
     539         [ +  - ]:         18 :         if (!feat_node_name)
     540                 :            :                 return -1;
     541                 :            : 
     542         [ +  - ]:         18 :         if (slot)
     543                 :         18 :                 *slot = 0;
     544                 :            : 
     545         [ +  + ]:         33 :         STAILQ_FOREACH(finfo, &arc->all_features, next_feature) {
     546         [ +  + ]:         16 :                 if (!strncmp(finfo->feature_name, feat_node_name, strlen(finfo->feature_name))) {
     547         [ +  - ]:          1 :                         if (ffinfo)
     548                 :          1 :                                 *ffinfo = finfo;
     549         [ +  - ]:          1 :                         if (slot)
     550                 :          1 :                                 *slot = fi;
     551                 :          1 :                         return 0;
     552                 :            :                 }
     553                 :            :                 /* Update slot where new feature can be added */
     554         [ +  - ]:         15 :                 if (slot)
     555                 :         15 :                         *slot = fi;
     556                 :         15 :                 fi++;
     557                 :            :         }
     558                 :            : 
     559                 :            :         return -1;
     560                 :            : }
     561                 :            : 
     562                 :            : /* Get control path node info from provided input feature_index */
     563                 :            : static int
     564                 :            : nodeinfo_lkup_by_index(struct rte_graph_feature_arc *arc, uint32_t feature_index,
     565                 :            :                        struct rte_graph_feature_node_list **ppfinfo,
     566                 :            :                        const int do_sanity_check)
     567                 :            : {
     568                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
     569                 :            :         uint32_t index = 0;
     570                 :            : 
     571                 :            :         if (!ppfinfo)
     572                 :            :                 return -1;
     573                 :            : 
     574                 :            :         *ppfinfo = NULL;
     575   [ +  -  +  -  :       4063 :         STAILQ_FOREACH(finfo, &arc->all_features, next_feature) {
          +  -  -  -  +  
                -  +  - ]
     576                 :            :                 /* Check sanity */
     577                 :            :                 if (do_sanity_check)
     578   [ +  -  +  - ]:       2673 :                         if (finfo->finfo_index != index)
     579                 :            :                                 return -1;
     580   [ +  +  +  +  :       4063 :                 if (index == feature_index) {
          +  +  -  -  +  
                +  +  + ]
     581                 :            :                         *ppfinfo = finfo;
     582                 :            :                         return 0;
     583                 :            :                 }
     584                 :       2616 :                 index++;
     585                 :            :         }
     586                 :            :         return -1;
     587                 :            : }
     588                 :            : 
     589                 :            : /* get existing edge from parent_node -> child_node */
     590                 :            : static int
     591                 :        258 : get_existing_edge(const char *arc_name, rte_node_t parent_node,
     592                 :            :                   rte_node_t child_node, rte_edge_t *_edge)
     593                 :            : {
     594                 :            :         char **next_edges = NULL;
     595                 :            :         uint32_t i, count = 0;
     596                 :            : 
     597                 :            :         RTE_SET_USED(arc_name);
     598                 :            : 
     599                 :        258 :         count = rte_node_edge_get(parent_node, NULL);
     600                 :            : 
     601         [ +  + ]:        258 :         if (!count)
     602                 :            :                 return -1;
     603                 :            : 
     604                 :        252 :         next_edges = malloc(count);
     605                 :            : 
     606         [ +  - ]:        252 :         if (!next_edges)
     607                 :            :                 return -1;
     608                 :            : 
     609                 :        252 :         count = rte_node_edge_get(parent_node, next_edges);
     610         [ +  + ]:        394 :         for (i = 0; i < count; i++) {
     611         [ +  + ]:        384 :                 if (strstr(rte_node_id_to_name(child_node), next_edges[i])) {
     612         [ +  - ]:        242 :                         if (_edge)
     613                 :        242 :                                 *_edge = (rte_edge_t)i;
     614                 :            : 
     615                 :        242 :                         free(next_edges);
     616                 :        242 :                         return 0;
     617                 :            :                 }
     618                 :            :         }
     619                 :         10 :         free(next_edges);
     620                 :            : 
     621                 :         10 :         return -1;
     622                 :            : }
     623                 :            : 
     624                 :            : 
     625                 :            : /* prepare feature arc after addition of all features */
     626                 :            : static int
     627                 :          3 : prepare_feature_arc_before_first_enable(struct rte_graph_feature_arc *arc)
     628                 :            : {
     629                 :            :         struct rte_graph_feature_node_list *lfinfo = NULL;
     630                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
     631                 :            :         char name[2 * RTE_GRAPH_FEATURE_ARC_NAMELEN];
     632                 :            :         uint32_t findex = 0, iter;
     633                 :            :         uint16_t num_fdata;
     634                 :            :         rte_edge_t edge;
     635                 :            :         size_t sz = 0;
     636                 :            : 
     637         [ +  + ]:         13 :         STAILQ_FOREACH(lfinfo, &arc->all_features, next_feature) {
     638                 :         10 :                 lfinfo->finfo_index = findex;
     639                 :         10 :                 findex++;
     640                 :            :         }
     641         [ -  + ]:          3 :         if (!findex) {
     642                 :          0 :                 graph_err("No feature added to arc: %s", arc->feature_arc_name);
     643                 :          0 :                 return -1;
     644                 :            :         }
     645                 :          3 :         arc->num_added_features = findex;
     646                 :          3 :         num_fdata = arc->num_added_features + NUM_EXTRA_FEATURE_DATA;
     647                 :            : 
     648                 :          3 :         sz = num_fdata * arc->max_indexes * sizeof(rte_graph_feature_data_t);
     649                 :            : 
     650                 :          3 :         snprintf(name, sizeof(name), "%s-fdata", arc->feature_arc_name);
     651                 :            : 
     652                 :          3 :         arc->feature_data_by_index = rte_malloc(name, sz, 0);
     653         [ -  + ]:          3 :         if (!arc->feature_data_by_index) {
     654                 :          0 :                 graph_err("fdata/index rte_malloc failed for %s", name);
     655                 :          0 :                 return -1;
     656                 :            :         }
     657                 :            : 
     658         [ +  + ]:       1699 :         for (iter = 0; iter < (num_fdata * arc->max_indexes); iter++)
     659                 :       1696 :                 arc->feature_data_by_index[iter] = RTE_GRAPH_FEATURE_DATA_INVALID;
     660                 :            : 
     661                 :            :         /* Grab finfo corresponding to end_feature */
     662                 :          3 :         nodeinfo_lkup_by_index(arc, arc->num_added_features - 1, &lfinfo, 0);
     663                 :            : 
     664                 :            :         /* lfinfo should be the info corresponding to end_feature
     665                 :            :          * Add edge from all features to end feature node to have exception path
     666                 :            :          * in fast path from all feature nodes to end feature node during enable/disable
     667                 :            :          */
     668         [ -  + ]:          3 :         if (lfinfo->feature_node_id != arc->end_feature.feature_node_id) {
     669                 :          0 :                 graph_err("end_feature node mismatch [found-%s: exp-%s]",
     670                 :            :                           rte_node_id_to_name(lfinfo->feature_node_id),
     671                 :            :                           rte_node_id_to_name(arc->end_feature.feature_node_id));
     672                 :          0 :                 goto free_fdata_by_index;
     673                 :            :         }
     674                 :            : 
     675         [ +  + ]:         13 :         STAILQ_FOREACH(finfo, &arc->all_features, next_feature) {
     676         [ -  + ]:         10 :                 if (get_existing_edge(arc->feature_arc_name, arc->start_node->id,
     677                 :            :                                       finfo->feature_node_id, &edge)) {
     678                 :          0 :                         graph_err("No edge found from %s to %s",
     679                 :            :                                   rte_node_id_to_name(arc->start_node->id),
     680                 :            :                                   rte_node_id_to_name(finfo->feature_node_id));
     681                 :          0 :                         goto free_fdata_by_index;
     682                 :            :                 }
     683                 :         10 :                 finfo->edge_to_this_feature = edge;
     684                 :            : 
     685         [ +  + ]:         10 :                 if (finfo == lfinfo)
     686                 :          3 :                         continue;
     687                 :            : 
     688         [ -  + ]:          7 :                 if (get_existing_edge(arc->feature_arc_name, finfo->feature_node_id,
     689                 :            :                                       lfinfo->feature_node_id, &edge)) {
     690                 :          0 :                         graph_err("No edge found from %s to %s",
     691                 :            :                                   rte_node_id_to_name(finfo->feature_node_id),
     692                 :            :                                   rte_node_id_to_name(lfinfo->feature_node_id));
     693                 :          0 :                         goto free_fdata_by_index;
     694                 :            :                 }
     695                 :          7 :                 finfo->edge_to_last_feature = edge;
     696                 :            :         }
     697                 :            :         /**
     698                 :            :          * Enable end_feature in control bitmask
     699                 :            :          * (arc->feature_bit_mask_by_index) but not in fast path bitmask
     700                 :            :          * arc->fp_feature_enable_bitmask. This is due to:
     701                 :            :          * 1. Application may not explicitly enabling end_feature node
     702                 :            :          * 2. However it should be enabled internally so that when a feature is
     703                 :            :          *    disabled (say on an interface), next_edge of data should be
     704                 :            :          *    updated to end_feature node hence packet can exit arc.
     705                 :            :          * 3. We do not want to set bit for end_feature in fast path bitmask as
     706                 :            :          *    it will void the purpose of fast path APIs
     707                 :            :          *    rte_graph_feature_arc_is_any_feature_enabled(). Since enabling
     708                 :            :          *    end_feature would make these APIs to always return "true"
     709                 :            :          */
     710         [ +  + ]:        291 :         for (iter = 0; iter < arc->max_indexes; iter++)
     711                 :        288 :                 arc->feature_bit_mask_by_index[iter] |= (1 << lfinfo->finfo_index);
     712                 :            : 
     713                 :            :         return 0;
     714                 :            : 
     715                 :          0 : free_fdata_by_index:
     716                 :          0 :         rte_free(arc->feature_data_by_index);
     717                 :          0 :         return -1;
     718                 :            : }
     719                 :            : 
     720                 :            : /* feature arc sanity */
     721                 :            : static int
     722                 :         18 : feature_arc_sanity(rte_graph_feature_arc_t _arc)
     723                 :            : {
     724         [ +  - ]:         18 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
     725                 :            :         rte_graph_feature_arc_main_t *dm = __rte_graph_feature_arc_main;
     726                 :            :         uint16_t iter;
     727                 :            : 
     728         [ +  - ]:         18 :         if (!__rte_graph_feature_arc_main)
     729                 :            :                 return -1;
     730                 :            : 
     731         [ +  - ]:         18 :         if (!arc)
     732                 :            :                 return -1;
     733                 :            : 
     734         [ +  - ]:         40 :         for (iter = 0; iter < dm->max_feature_arcs; iter++) {
     735   [ +  -  +  + ]:         80 :                 if (arc == rte_graph_feature_arc_get(iter)) {
     736         [ +  - ]:         18 :                         if (arc->feature_arc_index != iter)
     737                 :            :                                 return -1;
     738         [ +  - ]:         18 :                         if (arc->feature_arc_main != dm)
     739                 :            :                                 return -1;
     740                 :            : 
     741                 :         18 :                         return 0;
     742                 :            :                 }
     743                 :            :         }
     744                 :            :         return -1;
     745                 :            : }
     746                 :            : 
     747                 :            : /* create or retrieve already existing edge from parent_node -> child_node */
     748                 :            : static int
     749                 :         38 : __connect_graph_nodes(rte_node_t parent_node, rte_node_t child_node,
     750                 :            :                     rte_edge_t *_edge, char *arc_name, int lineno)
     751                 :            : {
     752                 :         38 :         const char *next_node = NULL;
     753                 :            :         rte_edge_t edge;
     754                 :            : 
     755         [ +  + ]:         38 :         if (!get_existing_edge(arc_name, parent_node, child_node, &edge)) {
     756                 :         22 :                 feat_dbg("\t%s/%d: %s[%u]: \"%s\", edge reused", arc_name, lineno,
     757                 :            :                          rte_node_id_to_name(parent_node), edge, rte_node_id_to_name(child_node));
     758                 :            : 
     759         [ +  + ]:         22 :                 if (_edge)
     760                 :         12 :                         *_edge = edge;
     761                 :            : 
     762                 :         22 :                 return 0;
     763                 :            :         }
     764                 :            : 
     765                 :            :         /* Node to be added */
     766                 :         16 :         next_node = rte_node_id_to_name(child_node);
     767                 :            : 
     768                 :         16 :         edge = rte_node_edge_update(parent_node, RTE_EDGE_ID_INVALID, &next_node, 1);
     769                 :            : 
     770         [ -  + ]:         16 :         if (edge == RTE_EDGE_ID_INVALID) {
     771                 :          0 :                 graph_err("edge invalid");
     772                 :          0 :                 return -1;
     773                 :            :         }
     774                 :         16 :         edge = rte_node_edge_count(parent_node) - 1;
     775                 :            : 
     776                 :         16 :         feat_dbg("\t%s/%d: %s[%u]: \"%s\", new edge added", arc_name, lineno,
     777                 :            :                  rte_node_id_to_name(parent_node), edge, rte_node_id_to_name(child_node));
     778                 :            : 
     779         [ +  + ]:         16 :         if (_edge)
     780                 :         10 :                 *_edge = edge;
     781                 :            : 
     782                 :            :         return 0;
     783                 :            : }
     784                 :            : 
     785                 :            : /* feature arc initialization */
     786                 :            : static int
     787                 :          2 : feature_arc_main_init(rte_graph_feature_arc_main_t **pfl, uint32_t max_feature_arcs)
     788                 :            : {
     789                 :            :         rte_graph_feature_arc_main_t *pm = NULL;
     790                 :            :         const struct rte_memzone *mz = NULL;
     791                 :            :         uint32_t i;
     792                 :            :         size_t sz;
     793                 :            : 
     794         [ -  + ]:          2 :         if (!pfl) {
     795                 :          0 :                 graph_err("Invalid input");
     796                 :          0 :                 return -1;
     797                 :            :         }
     798                 :            : 
     799                 :          2 :         sz = sizeof(rte_graph_feature_arc_main_t) +
     800                 :            :                 (sizeof(pm->feature_arcs[0]) * max_feature_arcs);
     801                 :            : 
     802                 :          2 :         mz = rte_memzone_reserve(FEATURE_ARC_MEMZONE_NAME, sz, SOCKET_ID_ANY, 0);
     803         [ -  + ]:          2 :         if (!mz) {
     804                 :          0 :                 graph_err("memzone reserve failed for feature arc main");
     805                 :          0 :                 return -1;
     806                 :            :         }
     807                 :            : 
     808                 :          2 :         pm = mz->addr;
     809                 :            :         memset(pm, 0, sz);
     810                 :            : 
     811                 :          2 :         pm->arc_mbuf_dyn_offset = -1;
     812                 :          2 :         pm->arc_mbuf_dyn_offset = rte_mbuf_dynfield_register(&rte_graph_feature_arc_mbuf_desc);
     813                 :            : 
     814         [ -  + ]:          2 :         if (pm->arc_mbuf_dyn_offset < 0) {
     815                 :          0 :                 graph_err("rte_graph_feature_arc_dynfield_register failed");
     816                 :          0 :                 rte_memzone_free(mz);
     817                 :          0 :                 return -1;
     818                 :            :         }
     819         [ +  + ]:         25 :         for (i = 0; i < max_feature_arcs; i++)
     820                 :         23 :                 pm->feature_arcs[i] = GRAPH_FEATURE_ARC_PTR_INITIALIZER;
     821                 :            : 
     822                 :          2 :         pm->max_feature_arcs = max_feature_arcs;
     823                 :            : 
     824                 :          2 :         *pfl = pm;
     825                 :            : 
     826                 :          2 :         return 0;
     827                 :            : }
     828                 :            : 
     829                 :            : static int
     830                 :        547 : feature_enable_disable_validate(rte_graph_feature_arc_t _arc, uint32_t index,
     831                 :            :                                 const char *feature_name,
     832                 :            :                                 int is_enable_disable, bool emit_logs)
     833                 :            : {
     834         [ +  - ]:        547 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
     835                 :        547 :         struct rte_graph_feature_node_list *finfo = NULL;
     836                 :            :         uint32_t slot, last_end_feature;
     837                 :            : 
     838         [ -  + ]:        547 :         if (!arc)
     839                 :          0 :                 return -EINVAL;
     840                 :            : 
     841                 :            :         /* validate _arc */
     842         [ -  + ]:        547 :         if (arc->feature_arc_main != __rte_graph_feature_arc_main) {
     843         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "invalid feature arc: 0x%x", _arc);
     844                 :          0 :                 return -EINVAL;
     845                 :            :         }
     846                 :            : 
     847                 :            :         /* validate index */
     848         [ +  + ]:        547 :         if (index >= arc->max_indexes) {
     849         [ +  - ]:          1 :                 FEAT_COND_ERR(emit_logs, "%s: Invalid provided index: %u >= %u configured",
     850                 :            :                               arc->feature_arc_name, index, arc->max_indexes);
     851                 :          1 :                 return -1;
     852                 :            :         }
     853                 :            : 
     854                 :            :         /* validate feature_name is already added or not  */
     855         [ +  + ]:        546 :         if (nodeinfo_lkup_by_name(arc, feature_name, &finfo, &slot)) {
     856         [ +  - ]:          1 :                 FEAT_COND_ERR(emit_logs, "%s: No feature %s added",
     857                 :            :                               arc->feature_arc_name, feature_name);
     858                 :          1 :                 return -EINVAL;
     859                 :            :         }
     860                 :            : 
     861         [ -  + ]:        545 :         if (!finfo) {
     862         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s: No feature: %s found to enable/disable",
     863                 :            :                               arc->feature_arc_name, feature_name);
     864                 :          0 :                 return -EINVAL;
     865                 :            :         }
     866                 :            : 
     867                 :            :         /* slot should be in valid range */
     868         [ -  + ]:        545 :         if (slot >= arc->num_added_features) {
     869         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s/%s: Invalid free slot %u(max=%u) for feature",
     870                 :            :                               arc->feature_arc_name, feature_name, slot, arc->num_added_features);
     871                 :          0 :                 return -EINVAL;
     872                 :            :         }
     873                 :            : 
     874                 :            :         /* slot should be in range of 0 - 63 */
     875         [ -  + ]:        545 :         if (slot > (GRAPH_FEATURE_MAX_NUM_PER_ARC - 1)) {
     876         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s/%s: Invalid slot: %u", arc->feature_arc_name,
     877                 :            :                               feature_name, slot);
     878                 :          0 :                 return -EINVAL;
     879                 :            :         }
     880                 :            : 
     881         [ +  - ]:        545 :         last_end_feature = rte_fls_u64(arc->feature_bit_mask_by_index[index]);
     882                 :            :         if (!last_end_feature) {
     883         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s: End feature not enabled", arc->feature_arc_name);
     884                 :          0 :                 return -EINVAL;
     885                 :            :         }
     886                 :            : 
     887                 :            :         /* if enabled feature is not end feature node and already enabled */
     888   [ +  +  +  + ]:        545 :         if (is_enable_disable &&
     889                 :         70 :             (arc->feature_bit_mask_by_index[index] & RTE_BIT64(slot)) &&
     890         [ +  + ]:         70 :             (slot != (last_end_feature - 1))) {
     891         [ +  - ]:          1 :                 FEAT_COND_ERR(emit_logs, "%s: %s already enabled on index: %u",
     892                 :            :                               arc->feature_arc_name, feature_name, index);
     893                 :          1 :                 return -1;
     894                 :            :         }
     895                 :            : 
     896   [ +  +  -  + ]:        544 :         if (!is_enable_disable && !arc->runtime_enabled_features) {
     897         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s: No feature enabled to disable",
     898                 :            :                               arc->feature_arc_name);
     899                 :          0 :                 return -1;
     900                 :            :         }
     901                 :            : 
     902   [ +  +  -  + ]:        544 :         if (!is_enable_disable && !(arc->feature_bit_mask_by_index[index] & RTE_BIT64(slot))) {
     903         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs, "%s: %s not enabled in bitmask for index: %u",
     904                 :            :                               arc->feature_arc_name, feature_name, index);
     905                 :          0 :                 return -1;
     906                 :            :         }
     907                 :            : 
     908                 :            :         /* If no feature has been enabled, avoid extra sanity checks */
     909         [ +  + ]:        544 :         if (!arc->runtime_enabled_features)
     910                 :            :                 return 0;
     911                 :            : 
     912         [ -  + ]:        542 :         if (finfo->finfo_index != slot) {
     913         [ #  # ]:          0 :                 FEAT_COND_ERR(emit_logs,
     914                 :            :                               "%s/%s: lookup slot mismatch for finfo idx: %u and lookup slot: %u",
     915                 :            :                               arc->feature_arc_name, feature_name, finfo->finfo_index, slot);
     916                 :          0 :                 return -1;
     917                 :            :         }
     918                 :            : 
     919                 :            :         return 0;
     920                 :            : }
     921                 :            : 
     922                 :            : static int
     923                 :        544 : refill_fastpath_data(struct rte_graph_feature_arc *arc, uint32_t feature_bit,
     924                 :            :                      uint16_t index /* array index */, int is_enable_disable)
     925                 :            : {
     926                 :            :         struct rte_graph_feature_data *gfd = NULL, *prev_gfd = NULL, *fdptr = NULL;
     927                 :            :         struct rte_graph_feature_node_list *finfo = NULL, *prev_finfo = NULL;
     928                 :            :         RTE_ATOMIC(rte_graph_feature_data_t) * first_fdata = NULL;
     929                 :            :         uint32_t fi = 0, prev_fi = 0, next_fi = 0, cfi = 0;
     930                 :            :         uint64_t bitmask = 0, prev_bitmask, next_bitmask;
     931                 :            :         rte_graph_feature_data_t *__first_fd = NULL;
     932                 :        544 :         rte_edge_t edge = RTE_EDGE_ID_INVALID;
     933                 :            :         rte_graph_feature_data_t fdata, _fd;
     934                 :            :         bool update_first_feature = false;
     935                 :            : 
     936         [ +  + ]:        544 :         if (is_enable_disable)
     937                 :        272 :                 bitmask = RTE_BIT64(feature_bit);
     938                 :            : 
     939                 :            :         /* set bit from (feature_bit + 1) to 64th bit */
     940                 :        544 :         next_bitmask = UINT64_MAX << (feature_bit + 1);
     941                 :            : 
     942                 :            :         /* set bits from 0 to (feature_bit - 1) */
     943                 :        544 :         prev_bitmask = ((UINT64_MAX & ~next_bitmask) & ~(RTE_BIT64(feature_bit)));
     944                 :            : 
     945                 :        544 :         next_bitmask &= arc->feature_bit_mask_by_index[index];
     946         [ +  + ]:        544 :         prev_bitmask &= arc->feature_bit_mask_by_index[index];
     947                 :            : 
     948                 :            :         /* Set next bit set in next_bitmask */
     949                 :            :         if (rte_bsf64_safe(next_bitmask, &next_fi))
     950                 :        406 :                 bitmask |= RTE_BIT64(next_fi);
     951                 :            : 
     952                 :            :         /* Set prev bit set in prev_bitmask*/
     953                 :            :         prev_fi = rte_fls_u64(prev_bitmask);
     954                 :            :         if (prev_fi)
     955                 :          0 :                 bitmask |= RTE_BIT64(prev_fi - 1);
     956                 :            : 
     957                 :            :         /* for each feature set for index, set fast path data */
     958                 :            :         prev_gfd = NULL;
     959                 :            :         while (rte_bsf64_safe(bitmask, &fi)) {
     960                 :        678 :                 _fd = fdata_reserve(arc, fi, index);
     961                 :            :                 gfd = rte_graph_feature_data_get(arc, _fd);
     962                 :            : 
     963                 :            :                 if (nodeinfo_lkup_by_index(arc, fi, &finfo, 1) < 0) {
     964                 :          0 :                         graph_err("[%s/index:%2u,cookie:%u]: No finfo found for index: %u",
     965                 :            :                                   arc->feature_arc_name, index, gfd->app_cookie, fi);
     966                 :          0 :                         return -1;
     967                 :            :                 }
     968                 :            : 
     969                 :            :                 /* Reset next edge to point to last feature node so that packet
     970                 :            :                  * can exit from arc
     971                 :            :                  */
     972                 :        678 :                 rte_atomic_store_explicit(&gfd->next_edge,
     973                 :            :                                           finfo->edge_to_last_feature,
     974                 :            :                                           rte_memory_order_relaxed);
     975                 :            : 
     976                 :            :                 /* If previous feature_index was valid in last loop */
     977         [ +  + ]:        678 :                 if (prev_gfd != NULL) {
     978                 :            :                         /*
     979                 :            :                          * Get edge of previous feature node connecting
     980                 :            :                          * to this feature node
     981                 :            :                          */
     982                 :            :                         if (nodeinfo_lkup_by_index(arc, prev_fi, &prev_finfo, 1) < 0) {
     983                 :          0 :                                 graph_err("[%s/index:%2u,cookie:%u]: No prev_finfo found idx: %u",
     984                 :            :                                           arc->feature_arc_name, index, gfd->app_cookie, prev_fi);
     985                 :          0 :                                 return -1;
     986                 :            :                         }
     987                 :            : 
     988         [ +  - ]:        203 :                         if (!get_existing_edge(arc->feature_arc_name,
     989                 :            :                                               prev_finfo->feature_node_id,
     990                 :            :                                               finfo->feature_node_id, &edge)) {
     991                 :        203 :                                 feat_dbg("\t[%s/index:%2u,cookie:%u]: (%u->%u)%s[%u] = %s",
     992                 :            :                                          arc->feature_arc_name, index,
     993                 :            :                                          gfd->app_cookie, prev_fi, fi,
     994                 :            :                                          rte_node_id_to_name(prev_finfo->feature_node_id),
     995                 :            :                                          edge, rte_node_id_to_name(finfo->feature_node_id));
     996                 :            : 
     997                 :        203 :                                 rte_atomic_store_explicit(&prev_gfd->next_edge,
     998                 :            :                                                           edge,
     999                 :            :                                                           rte_memory_order_relaxed);
    1000                 :            : 
    1001                 :        203 :                                 rte_atomic_store_explicit(&prev_gfd->next_feature_data, _fd,
    1002                 :            :                                                           rte_memory_order_relaxed);
    1003                 :            :                         } else {
    1004                 :            :                                 /* Should not fail */
    1005                 :          0 :                                 graph_err("[%s/index:%2u,cookie:%u]: No edge found from %s to %s",
    1006                 :            :                                           arc->feature_arc_name, index, gfd->app_cookie,
    1007                 :            :                                           rte_node_id_to_name(prev_finfo->feature_node_id),
    1008                 :            :                                           rte_node_id_to_name(finfo->feature_node_id));
    1009                 :          0 :                                 return -1;
    1010                 :            :                         }
    1011                 :            :                 }
    1012                 :            :                 /* On first feature
    1013                 :            :                  * 1. Update fdata with next_edge from start_node to feature node
    1014                 :            :                  * 2. Update first enabled feature in its index array
    1015                 :            :                  */
    1016         [ +  - ]:        678 :                 if (rte_bsf64_safe(arc->feature_bit_mask_by_index[index], &cfi)) {
    1017                 :            :                         update_first_feature = (cfi == fi) ? true : false;
    1018                 :            : 
    1019         [ +  + ]:        678 :                         if (update_first_feature) {
    1020                 :        475 :                                 feat_dbg("\t[%s/index:%2u,cookie:%u]: (->%u)%s[%u]=%s",
    1021                 :            :                                          arc->feature_arc_name, index,
    1022                 :            :                                          gfd->app_cookie, fi,
    1023                 :            :                                          arc->start_node->name, finfo->edge_to_this_feature,
    1024                 :            :                                          rte_node_id_to_name(finfo->feature_node_id));
    1025                 :            : 
    1026                 :            :                                 /* Reserve feature data @0th index for first feature */
    1027                 :            :                                 fdata = first_fdata_reserve(arc, index);
    1028                 :            :                                 fdptr = rte_graph_feature_data_get(arc, fdata);
    1029                 :            : 
    1030                 :            :                                 /* add next edge into feature data
    1031                 :            :                                  * First set feature data then first feature memory
    1032                 :            :                                  */
    1033                 :        475 :                                 rte_atomic_store_explicit(&fdptr->next_edge,
    1034                 :            :                                                           finfo->edge_to_this_feature,
    1035                 :            :                                                           rte_memory_order_relaxed);
    1036                 :            : 
    1037                 :        475 :                                 rte_atomic_store_explicit(&fdptr->next_feature_data,
    1038                 :            :                                                           _fd,
    1039                 :            :                                                           rte_memory_order_relaxed);
    1040                 :            : 
    1041                 :            :                                 __first_fd = graph_first_feature_data_ptr_get(arc, index);
    1042                 :            :                                 first_fdata = (RTE_ATOMIC(rte_graph_feature_data_t) *)__first_fd;
    1043                 :            : 
    1044                 :            :                                 /* Save reserved feature data @fp_index */
    1045                 :        475 :                                 rte_atomic_store_explicit(first_fdata, fdata,
    1046                 :            :                                                           rte_memory_order_relaxed);
    1047                 :            :                         }
    1048                 :            :                 }
    1049                 :            :                 prev_fi = fi;
    1050                 :            :                 prev_gfd = gfd;
    1051                 :            :                 /* Clear current feature index */
    1052                 :        678 :                 bitmask &= ~RTE_BIT64(fi);
    1053                 :            :         }
    1054                 :            :         /* If all features are disabled on index, except end feature
    1055                 :            :          * then release 0th index
    1056                 :            :          */
    1057   [ +  +  +  - ]:        544 :         if (!is_enable_disable &&
    1058         [ +  - ]:        272 :             (rte_popcount64(arc->feature_bit_mask_by_index[index]) == 1))
    1059                 :        272 :                 first_fdata_release(arc, index);
    1060                 :            : 
    1061                 :            :         return 0;
    1062                 :            : }
    1063                 :            : 
    1064                 :            : /* feature arc initialization, public API */
    1065                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_init, 25.07)
    1066                 :            : int
    1067                 :          2 : rte_graph_feature_arc_init(uint16_t num_feature_arcs)
    1068                 :            : {
    1069                 :            :         struct rte_graph_feature_arc_register *arc_reg = NULL;
    1070                 :            :         struct rte_graph_feature_register *feat_reg = NULL;
    1071                 :            :         const struct rte_memzone *mz = NULL;
    1072                 :            :         int max_feature_arcs;
    1073                 :            :         int rc = -1;
    1074                 :            : 
    1075         [ +  - ]:          2 :         if (!__rte_graph_feature_arc_main) {
    1076                 :          2 :                 mz = rte_memzone_lookup(FEATURE_ARC_MEMZONE_NAME);
    1077         [ -  + ]:          2 :                 if (mz) {
    1078                 :          0 :                         __rte_graph_feature_arc_main = mz->addr;
    1079                 :          0 :                         return 0;
    1080                 :            :                 }
    1081                 :          2 :                 max_feature_arcs = num_feature_arcs + arc_registration_num();
    1082         [ -  + ]:          2 :                 if (!max_feature_arcs) {
    1083                 :          0 :                         graph_err("No feature arcs registered");
    1084                 :          0 :                         return -1;
    1085                 :            :                 }
    1086                 :          2 :                 rc = feature_arc_main_init(&__rte_graph_feature_arc_main, max_feature_arcs);
    1087         [ +  - ]:          2 :                 if (rc < 0)
    1088                 :            :                         return rc;
    1089                 :            :         }
    1090                 :            : 
    1091         [ +  + ]:         20 :         STAILQ_FOREACH(arc_reg, &feature_arc_list, next_arc) {
    1092         [ +  + ]:         18 :                 if (arc_registration_validate(arc_reg, __func__, __LINE__, true) < 0)
    1093                 :         14 :                         continue;
    1094                 :            : 
    1095                 :            :                 /* arc lookup validates feature and arc both*/
    1096         [ -  + ]:          4 :                 if (!arc_registration_lookup(arc_reg->arc_name, NULL, false))
    1097                 :          0 :                         continue;
    1098                 :            : 
    1099                 :            :                 /* If feature name not set, use node name as feature */
    1100         [ -  + ]:          4 :                 if (!arc_reg->end_feature->feature_name)
    1101                 :          0 :                         arc_reg->end_feature->feature_name =
    1102                 :          0 :                                 rte_node_id_to_name(arc_reg->end_feature->feature_node_id);
    1103                 :            : 
    1104                 :            :                 /* Compute number of max_features if not provided */
    1105         [ +  + ]:          4 :                 if (!arc_reg->max_features)
    1106                 :          2 :                         arc_registered_features_num(arc_reg->arc_name, &arc_reg->max_features);
    1107                 :            : 
    1108                 :          4 :                 rc = arc_max_index_get(arc_reg->arc_name, &arc_reg->max_indexes);
    1109         [ -  + ]:          4 :                 if (rc < 0) {
    1110                 :          0 :                         graph_err("arc_max_index_get failed for arc: %s",
    1111                 :            :                                   arc_reg->arc_name);
    1112                 :          0 :                         continue;
    1113                 :            :                 }
    1114                 :            : 
    1115                 :          4 :                 arc_reg->end_feature->feature_node_id = arc_reg->end_feature->feature_node->id;
    1116                 :            : 
    1117                 :          4 :                 rc = rte_graph_feature_arc_create(arc_reg, NULL);
    1118                 :            : 
    1119         [ -  + ]:          4 :                 if (rc < 0)
    1120                 :          0 :                         goto arc_cleanup;
    1121                 :            :         }
    1122                 :            : 
    1123                 :            :         /* First add those features which has no runs_after and runs_before restriction */
    1124         [ +  + ]:         10 :         STAILQ_FOREACH(feat_reg, &feature_list, next_feature) {
    1125                 :            :                 /* Skip if arc not registered yet */
    1126         [ +  + ]:          8 :                 if (!arc_registration_lookup(feat_reg->arc_name, NULL, false))
    1127                 :          2 :                         continue;
    1128                 :            : 
    1129   [ +  +  -  + ]:          6 :                 if (feat_reg->runs_after || feat_reg->runs_before)
    1130                 :          4 :                         continue;
    1131                 :            : 
    1132         [ -  + ]:          2 :                 if (feature_registration_validate(feat_reg, __func__, __LINE__, 1, 0, false) < 0)
    1133                 :          0 :                         continue;
    1134                 :            : 
    1135                 :          2 :                 feat_reg->feature_node_id = feat_reg->feature_node->id;
    1136                 :            : 
    1137                 :          2 :                 rc = rte_graph_feature_add(feat_reg);
    1138                 :            : 
    1139         [ -  + ]:          2 :                 if (rc < 0)
    1140                 :          0 :                         goto arc_cleanup;
    1141                 :            :         }
    1142                 :            :         /* Add those features which has either runs_after or runs_before restrictions */
    1143         [ +  + ]:         10 :         STAILQ_FOREACH(feat_reg, &feature_list, next_feature) {
    1144                 :            :                 /* Skip if arc not registered yet */
    1145         [ +  + ]:          8 :                 if (!arc_registration_lookup(feat_reg->arc_name, NULL, false))
    1146                 :          2 :                         continue;
    1147                 :            : 
    1148   [ +  +  +  - ]:          6 :                 if (!feat_reg->runs_after && !feat_reg->runs_before)
    1149                 :          2 :                         continue;
    1150                 :            : 
    1151   [ +  -  +  + ]:          4 :                 if (feat_reg->runs_after && feat_reg->runs_before)
    1152                 :          2 :                         continue;
    1153                 :            : 
    1154         [ -  + ]:          2 :                 if (feature_registration_validate(feat_reg, __func__, __LINE__, 1, 0, false) < 0)
    1155                 :          0 :                         continue;
    1156                 :            : 
    1157                 :          2 :                 feat_reg->feature_node_id = feat_reg->feature_node->id;
    1158                 :            : 
    1159                 :          2 :                 rc = rte_graph_feature_add(feat_reg);
    1160                 :            : 
    1161         [ -  + ]:          2 :                 if (rc < 0)
    1162                 :          0 :                         goto arc_cleanup;
    1163                 :            :         }
    1164                 :            :         /* Add those features with both runs_after and runs_before restrictions */
    1165         [ +  + ]:         10 :         STAILQ_FOREACH(feat_reg, &feature_list, next_feature) {
    1166                 :            :                 /* Skip if arc not registered yet */
    1167         [ +  + ]:          8 :                 if (!arc_registration_lookup(feat_reg->arc_name, NULL, false))
    1168                 :          2 :                         continue;
    1169                 :            : 
    1170   [ +  +  +  - ]:          6 :                 if (!feat_reg->runs_after && !feat_reg->runs_before)
    1171                 :          2 :                         continue;
    1172                 :            : 
    1173   [ +  -  +  +  :          4 :                 if ((feat_reg->runs_after && !feat_reg->runs_before) ||
                   -  + ]
    1174         [ #  # ]:          0 :                     (!feat_reg->runs_after && feat_reg->runs_before))
    1175                 :          2 :                         continue;
    1176                 :            : 
    1177         [ -  + ]:          2 :                 if (feature_registration_validate(feat_reg, __func__, __LINE__, 1, 0, false) < 0)
    1178                 :          0 :                         continue;
    1179                 :            : 
    1180                 :          2 :                 feat_reg->feature_node_id = feat_reg->feature_node->id;
    1181                 :            : 
    1182                 :          2 :                 rc = rte_graph_feature_add(feat_reg);
    1183                 :            : 
    1184         [ -  + ]:          2 :                 if (rc < 0)
    1185                 :          0 :                         goto arc_cleanup;
    1186                 :            :         }
    1187                 :            : 
    1188                 :            :         return 0;
    1189                 :            : 
    1190                 :          0 : arc_cleanup:
    1191                 :          0 :         rte_graph_feature_arc_cleanup();
    1192                 :            : 
    1193                 :          0 :         return rc;
    1194                 :            : }
    1195                 :            : 
    1196                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_create, 25.07)
    1197                 :            : int
    1198                 :         10 : rte_graph_feature_arc_create(struct rte_graph_feature_arc_register *reg,
    1199                 :            :                              rte_graph_feature_arc_t *_arc)
    1200                 :            : {
    1201                 :            :         rte_graph_feature_arc_main_t *dfm = NULL;
    1202                 :            :         struct rte_graph_feature_arc *arc = NULL;
    1203                 :            :         uint16_t first_feat_off, fdata_off;
    1204                 :            :         const struct rte_memzone *mz = NULL;
    1205                 :            :         uint16_t iter, arc_index, num_index;
    1206                 :            :         uint32_t feat_sz = 0;
    1207                 :            :         size_t sz;
    1208                 :            : 
    1209         [ +  - ]:         10 :         if (arc_registration_validate(reg, __func__, __LINE__, true) < 0)
    1210                 :            :                 return -1;
    1211                 :            : 
    1212   [ +  -  -  + ]:         20 :         if (!reg->end_feature ||
    1213                 :         10 :             (feature_registration_validate(reg->end_feature, __func__, __LINE__, 0, 1, true) < 0))
    1214                 :          0 :                 return -1;
    1215                 :            : 
    1216         [ -  + ]:         10 :         if (!reg->max_features)
    1217                 :          0 :                 graph_err("Zero features found for arc \"%s\" create",
    1218                 :            :                           reg->arc_name);
    1219                 :            : 
    1220         [ -  + ]:         10 :         if (!__rte_graph_feature_arc_main) {
    1221                 :          0 :                 graph_err("Call to rte_graph_feature_arc_init() API missing");
    1222                 :          0 :                 return -1;
    1223                 :            :         }
    1224                 :            : 
    1225                 :            :         /* See if arc memory is already created */
    1226                 :         10 :         mz = rte_memzone_lookup(reg->arc_name);
    1227         [ +  + ]:         10 :         if (mz) {
    1228                 :          1 :                 graph_err("Feature arc %s already created", reg->arc_name);
    1229                 :            :                 arc = mz->addr;
    1230                 :          1 :                 return -1;
    1231                 :            :         }
    1232                 :            : 
    1233                 :          9 :         dfm = __rte_graph_feature_arc_main;
    1234                 :            : 
    1235                 :            :         /* threshold check */
    1236         [ -  + ]:          9 :         if (dfm->num_feature_arcs > (dfm->max_feature_arcs - 1))
    1237                 :          0 :                 SET_ERR_JMP(EAGAIN, arc_create_err,
    1238                 :            :                             "%s: max number (%u) of feature arcs reached",
    1239                 :            :                             reg->arc_name, dfm->max_feature_arcs);
    1240                 :            : 
    1241                 :            :         /* Find the free slot for feature arc */
    1242         [ +  - ]:         27 :         for (iter = 0; iter < dfm->max_feature_arcs; iter++) {
    1243         [ +  + ]:         27 :                 if (dfm->feature_arcs[iter] == GRAPH_FEATURE_ARC_PTR_INITIALIZER)
    1244                 :            :                         break;
    1245                 :            :         }
    1246                 :            :         arc_index = iter;
    1247                 :            : 
    1248         [ -  + ]:          9 :         if (arc_index >= dfm->max_feature_arcs) {
    1249                 :          0 :                 graph_err("No free slot found for num_feature_arc");
    1250                 :          0 :                 return -1;
    1251                 :            :         }
    1252                 :            : 
    1253                 :            :         /* This should not happen */
    1254         [ -  + ]:          9 :         if (dfm->feature_arcs[arc_index] != GRAPH_FEATURE_ARC_PTR_INITIALIZER) {
    1255                 :          0 :                 graph_err("Free arc_index: %u is not found free: %p",
    1256                 :            :                           arc_index, (void *)dfm->feature_arcs[arc_index]);
    1257                 :          0 :                 return -1;
    1258                 :            :         }
    1259                 :            : 
    1260                 :            :         /* Calculate size of feature arc */
    1261                 :            :         feature_arc_reg_calc_size(reg, &sz, &first_feat_off, &fdata_off, &feat_sz, &num_index);
    1262                 :            : 
    1263                 :          9 :         mz = rte_memzone_reserve(reg->arc_name, sz, SOCKET_ID_ANY, 0);
    1264                 :            : 
    1265         [ -  + ]:          9 :         if (!mz) {
    1266                 :          0 :                 graph_err("memzone reserve failed for arc: %s of size: %"PRIu64,
    1267                 :            :                           reg->arc_name, (uint64_t)sz);
    1268                 :          0 :                 return -1;
    1269                 :            :         }
    1270                 :            : 
    1271                 :          9 :         arc = mz->addr;
    1272                 :            : 
    1273                 :            :         memset(arc, 0, sz);
    1274                 :            : 
    1275                 :          9 :         arc->feature_bit_mask_by_index = rte_malloc(reg->arc_name,
    1276                 :            :                                                     sizeof(uint64_t) * num_index, 0);
    1277                 :            : 
    1278         [ -  + ]:          9 :         if (!arc->feature_bit_mask_by_index) {
    1279                 :          0 :                 graph_err("%s: rte_malloc failed for feature_bit_mask_alloc", reg->arc_name);
    1280                 :          0 :                 goto mz_free;
    1281                 :            :         }
    1282                 :            : 
    1283                 :            :         memset(arc->feature_bit_mask_by_index, 0, sizeof(uint64_t) * num_index);
    1284                 :            : 
    1285                 :            :         /* override process function with start_node */
    1286         [ -  + ]:          9 :         if (node_override_process_func(reg->start_node->id, reg->start_node_feature_process_fn)) {
    1287                 :          0 :                 graph_err("node_override_process_func failed for %s", reg->start_node->name);
    1288                 :          0 :                 goto feat_bitmask_free;
    1289                 :            :         }
    1290                 :          9 :         feat_dbg("arc-%s: node-%s process() overridden with %p",
    1291                 :            :                   reg->arc_name, reg->start_node->name,
    1292                 :            :                   reg->start_node_feature_process_fn);
    1293                 :            : 
    1294                 :            :         /* Initialize rte_graph port group fixed variables */
    1295                 :          9 :         STAILQ_INIT(&arc->all_features);
    1296                 :          9 :         rte_strscpy(arc->feature_arc_name, reg->arc_name, RTE_GRAPH_FEATURE_ARC_NAMELEN - 1);
    1297                 :          9 :         arc->feature_arc_main = (void *)dfm;
    1298                 :          9 :         arc->start_node = reg->start_node;
    1299                 :          9 :         memcpy(&arc->end_feature, reg->end_feature, sizeof(arc->end_feature));
    1300                 :          9 :         arc->arc_start_process = reg->start_node_feature_process_fn;
    1301                 :          9 :         arc->feature_arc_index = arc_index;
    1302                 :          9 :         arc->arc_size = sz;
    1303                 :            : 
    1304                 :            :         /* reset fast path arc variables */
    1305                 :          9 :         arc->max_features = reg->max_features;
    1306                 :          9 :         arc->max_indexes = num_index;
    1307                 :          9 :         arc->fp_first_feature_offset = first_feat_off;
    1308                 :          9 :         arc->fp_feature_data_offset = fdata_off;
    1309                 :          9 :         arc->feature_size = feat_sz;
    1310                 :          9 :         arc->mbuf_dyn_offset = dfm->arc_mbuf_dyn_offset;
    1311                 :            : 
    1312                 :          9 :         feature_arc_data_reset(arc);
    1313                 :            : 
    1314                 :          9 :         dfm->feature_arcs[arc->feature_arc_index] = (uintptr_t)arc;
    1315                 :          9 :         dfm->num_feature_arcs++;
    1316                 :            : 
    1317         [ -  + ]:          9 :         if (rte_graph_feature_add(reg->end_feature) < 0)
    1318                 :          0 :                 goto arc_destroy;
    1319                 :            : 
    1320         [ +  + ]:          9 :         if (_arc)
    1321                 :          5 :                 *_arc = (rte_graph_feature_arc_t)arc_index;
    1322                 :            : 
    1323                 :          9 :         feat_dbg("Feature arc %s[%p] created with max_features: %u and indexes: %u",
    1324                 :            :                  arc->feature_arc_name, (void *)arc, arc->max_features, arc->max_indexes);
    1325                 :            : 
    1326                 :          9 :         return 0;
    1327                 :            : 
    1328                 :            : arc_destroy:
    1329                 :          0 :         rte_graph_feature_arc_destroy(arc_index);
    1330                 :          0 : feat_bitmask_free:
    1331                 :          0 :         rte_free(arc->feature_bit_mask_by_index);
    1332                 :          0 : mz_free:
    1333                 :          0 :         rte_memzone_free(mz);
    1334                 :            : arc_create_err:
    1335                 :            :         return -1;
    1336                 :            : }
    1337                 :            : 
    1338                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_add, 25.07)
    1339                 :            : int
    1340                 :         18 : rte_graph_feature_add(struct rte_graph_feature_register *freg)
    1341                 :            : {
    1342                 :         18 :         struct rte_graph_feature_node_list *after_finfo = NULL, *before_finfo = NULL;
    1343                 :         18 :         struct rte_graph_feature_node_list *temp = NULL, *finfo = NULL;
    1344                 :            :         char feature_name[3 * RTE_GRAPH_FEATURE_ARC_NAMELEN];
    1345                 :            :         const char *runs_after = NULL, *runs_before = NULL;
    1346                 :            :         struct rte_graph_feature_arc *arc = NULL;
    1347                 :         18 :         uint32_t slot = UINT32_MAX, add_flag;
    1348                 :            :         rte_graph_feature_arc_t _arc;
    1349                 :            :         uint32_t num_features = 0;
    1350                 :            :         const char *nodename = NULL;
    1351                 :         18 :         rte_edge_t edge = -1;
    1352                 :            :         int rc = 0;
    1353                 :            : 
    1354         [ +  - ]:         18 :         if (feature_registration_validate(freg, __func__, __LINE__, 0, 1, true) < 0)
    1355                 :            :                 return -1;
    1356                 :            : 
    1357                 :            :         /* arc is valid */
    1358         [ -  + ]:         18 :         if (rte_graph_feature_arc_lookup_by_name(freg->arc_name, &_arc)) {
    1359                 :          0 :                 graph_err("%s_add: feature arc %s not found",
    1360                 :            :                           freg->feature_name, freg->arc_name);
    1361                 :          0 :                 return -1;
    1362                 :            :         }
    1363                 :            : 
    1364         [ -  + ]:         18 :         if (feature_arc_sanity(_arc)) {
    1365                 :          0 :                 graph_err("invalid feature arc: 0x%x", _arc);
    1366                 :          0 :                 return -1;
    1367                 :            :         }
    1368                 :            : 
    1369                 :            :         arc = rte_graph_feature_arc_get(_arc);
    1370                 :            : 
    1371         [ -  + ]:         18 :         if (arc->runtime_enabled_features) {
    1372                 :          0 :                 graph_err("adding features after enabling any one of them is not supported");
    1373                 :          0 :                 return -1;
    1374                 :            :         }
    1375                 :            : 
    1376                 :            :         /* When application calls rte_graph_feature_add() directly*/
    1377         [ -  + ]:         18 :         if (freg->feature_node_id == RTE_NODE_ID_INVALID) {
    1378                 :          0 :                 graph_err("%s/%s: Invalid feature_node_id set for %s",
    1379                 :            :                           freg->arc_name, freg->feature_name, __func__);
    1380                 :          0 :                 return -1;
    1381                 :            :         }
    1382                 :            : 
    1383   [ +  +  +  +  :         18 :         if ((freg->runs_after != NULL) && (freg->runs_before != NULL) &&
                   -  + ]
    1384                 :            :             (freg->runs_after == freg->runs_before)) {
    1385                 :          0 :                 graph_err("runs_after and runs_before cannot be same '%s:%s]", freg->runs_after,
    1386                 :            :                           freg->runs_before);
    1387                 :          0 :                 return -1;
    1388                 :            :         }
    1389                 :            : 
    1390                 :         18 :         num_features = rte_graph_feature_arc_num_features(_arc);
    1391         [ +  + ]:         18 :         if (num_features) {
    1392                 :          9 :                 nodeinfo_lkup_by_index(arc, num_features - 1, &temp, 0);
    1393                 :            :                 /* Check if feature is not added after end_feature */
    1394         [ +  + ]:          9 :                 if ((freg->runs_after != NULL) &&
    1395         [ -  + ]:          5 :                     (strncmp(freg->runs_after, temp->feature_name,
    1396                 :            :                              RTE_GRAPH_FEATURE_ARC_NAMELEN) == 0)) {
    1397                 :          0 :                         graph_err("Feature %s cannot be added after end_feature %s",
    1398                 :            :                                   freg->feature_name, freg->runs_after);
    1399                 :          0 :                         return -1;
    1400                 :            :                 }
    1401                 :            :         }
    1402                 :            : 
    1403         [ +  + ]:         18 :         if (!nodeinfo_add_lookup(arc, freg->feature_name, &finfo, &slot)) {
    1404                 :          1 :                 graph_err("%s/%s feature already added", arc->feature_arc_name, freg->feature_name);
    1405                 :          1 :                 return -1;
    1406                 :            :         }
    1407                 :            : 
    1408         [ -  + ]:         17 :         if (slot >= arc->max_features) {
    1409                 :          0 :                 graph_err("%s: Max features %u added to feature arc",
    1410                 :            :                           arc->feature_arc_name, slot);
    1411                 :          0 :                 return -1;
    1412                 :            :         }
    1413                 :            : 
    1414         [ -  + ]:         17 :         if (freg->feature_node_id == arc->start_node->id) {
    1415                 :          0 :                 graph_err("%s/%s: Feature node and start node are same %u",
    1416                 :            :                           freg->arc_name, freg->feature_name, freg->feature_node_id);
    1417                 :          0 :                 return -1;
    1418                 :            :         }
    1419                 :            : 
    1420                 :         17 :         nodename = rte_node_id_to_name(freg->feature_node_id);
    1421                 :            : 
    1422                 :         17 :         feat_dbg("%s: adding feature node: %s at feature index: %u", arc->feature_arc_name,
    1423                 :            :                  nodename, slot);
    1424                 :            : 
    1425         [ -  + ]:         17 :         if (connect_graph_nodes(arc->start_node->id, freg->feature_node_id, &edge,
    1426                 :            :                                 arc->feature_arc_name)) {
    1427                 :          0 :                 graph_err("unable to connect %s -> %s", arc->start_node->name, nodename);
    1428                 :          0 :                 return -1;
    1429                 :            :         }
    1430                 :            : 
    1431                 :         17 :         snprintf(feature_name, sizeof(feature_name), "%s-%s-finfo",
    1432                 :            :                  arc->feature_arc_name, freg->feature_name);
    1433                 :            : 
    1434                 :         17 :         finfo = rte_malloc(feature_name, sizeof(*finfo), 0);
    1435         [ -  + ]:         17 :         if (!finfo) {
    1436                 :          0 :                 graph_err("%s/%s: rte_malloc failed", arc->feature_arc_name, freg->feature_name);
    1437                 :          0 :                 return -1;
    1438                 :            :         }
    1439                 :            : 
    1440                 :            :         memset(finfo, 0, sizeof(*finfo));
    1441                 :            : 
    1442                 :         17 :         rte_strscpy(finfo->feature_name, freg->feature_name, RTE_GRAPH_FEATURE_ARC_NAMELEN - 1);
    1443                 :         17 :         finfo->feature_arc = (void *)arc;
    1444                 :         17 :         finfo->feature_node_id = freg->feature_node_id;
    1445                 :         17 :         finfo->feature_node_process_fn = freg->feature_process_fn;
    1446                 :         17 :         finfo->edge_to_this_feature = RTE_EDGE_ID_INVALID;
    1447                 :         17 :         finfo->edge_to_last_feature = RTE_EDGE_ID_INVALID;
    1448                 :         17 :         finfo->notifier_cb = freg->notifier_cb;
    1449                 :            : 
    1450                 :         17 :         runs_before = freg->runs_before;
    1451                 :         17 :         runs_after = freg->runs_after;
    1452                 :            : 
    1453                 :            :         /*
    1454                 :            :          * if no constraints given and provided feature is not the first feature,
    1455                 :            :          * explicitly set "runs_before" as end_feature.
    1456                 :            :          *
    1457                 :            :          * Handles the case:
    1458                 :            :          * arc_create(f1);
    1459                 :            :          * add(f2, NULL, NULL);
    1460                 :            :          */
    1461   [ +  +  +  + ]:         17 :         if (!runs_after && !runs_before && num_features)
    1462                 :          3 :                 runs_before = rte_graph_feature_arc_feature_to_name(_arc, num_features - 1);
    1463                 :            : 
    1464                 :            :         /* Check for before and after constraints */
    1465         [ +  + ]:         17 :         if (runs_before) {
    1466                 :            :                 /* runs_before sanity */
    1467         [ -  + ]:          5 :                 if (nodeinfo_lkup_by_name(arc, runs_before, &before_finfo, NULL))
    1468                 :          0 :                         SET_ERR_JMP(EINVAL, finfo_free,
    1469                 :            :                                      "runs_before feature name: %s does not exist", runs_before);
    1470                 :            : 
    1471         [ -  + ]:          5 :                 if (!before_finfo)
    1472                 :          0 :                         SET_ERR_JMP(EINVAL, finfo_free,
    1473                 :            :                                      "runs_before %s does not exist", runs_before);
    1474                 :            : 
    1475                 :            :                 /*
    1476                 :            :                  * Starting from 0 to runs_before, continue connecting edges
    1477                 :            :                  */
    1478                 :            :                 add_flag = 1;
    1479         [ +  + ]:         14 :                 STAILQ_FOREACH(temp, &arc->all_features, next_feature) {
    1480         [ +  + ]:          9 :                         if (!add_flag)
    1481                 :            :                                 /* Nodes after seeing "runs_before", finfo connects to temp*/
    1482                 :          2 :                                 connect_graph_nodes(finfo->feature_node_id, temp->feature_node_id,
    1483                 :            :                                                     NULL, arc->feature_arc_name);
    1484                 :            :                         /*
    1485                 :            :                          * As soon as we see runs_before. stop adding edges
    1486                 :            :                          */
    1487         [ +  + ]:          9 :                         if (!strncmp(temp->feature_name, runs_before, RTE_GRAPH_NAMESIZE)) {
    1488         [ -  + ]:          5 :                                 if (!connect_graph_nodes(finfo->feature_node_id,
    1489                 :            :                                                          temp->feature_node_id,
    1490                 :            :                                                          &edge, arc->feature_arc_name))
    1491                 :            :                                         add_flag = 0;
    1492                 :            :                         }
    1493                 :            : 
    1494         [ +  + ]:          4 :                         if (add_flag)
    1495                 :            :                                 /* Nodes before seeing "run_before" are connected to finfo */
    1496                 :          2 :                                 connect_graph_nodes(temp->feature_node_id, finfo->feature_node_id,
    1497                 :            :                                                     NULL, arc->feature_arc_name);
    1498                 :            :                 }
    1499                 :            :         }
    1500                 :            : 
    1501         [ +  + ]:         17 :         if (runs_after) {
    1502         [ -  + ]:          5 :                 if (nodeinfo_lkup_by_name(arc, runs_after, &after_finfo, NULL))
    1503                 :          0 :                         SET_ERR_JMP(EINVAL, finfo_free,
    1504                 :            :                                      "Invalid after feature_name %s", runs_after);
    1505                 :            : 
    1506         [ -  + ]:          5 :                 if (!after_finfo)
    1507                 :          0 :                         SET_ERR_JMP(EINVAL, finfo_free,
    1508                 :            :                                      "runs_after %s does not exist", runs_after);
    1509                 :            : 
    1510                 :            :                 /* Starting from runs_after to end continue connecting edges */
    1511                 :            :                 add_flag = 0;
    1512         [ +  + ]:         17 :                 STAILQ_FOREACH(temp, &arc->all_features, next_feature) {
    1513         [ +  + ]:         12 :                         if (add_flag)
    1514                 :            :                                 /* We have already seen runs_after now */
    1515                 :            :                                 /* Add all features as next node to current feature*/
    1516                 :          7 :                                 connect_graph_nodes(finfo->feature_node_id, temp->feature_node_id,
    1517                 :            :                                                     NULL, arc->feature_arc_name);
    1518                 :            :                         else
    1519                 :            :                                 /* Connect initial nodes to newly added node*/
    1520                 :          5 :                                 connect_graph_nodes(temp->feature_node_id, finfo->feature_node_id,
    1521                 :            :                                                     NULL, arc->feature_arc_name);
    1522                 :            : 
    1523                 :            :                         /* as soon as we see runs_after. start adding edges
    1524                 :            :                          * from next iteration
    1525                 :            :                          */
    1526         [ +  + ]:         12 :                         if (!strncmp(temp->feature_name, runs_after, RTE_GRAPH_NAMESIZE))
    1527                 :            :                                 add_flag = 1;
    1528                 :            :                 }
    1529                 :            : 
    1530                 :            :                 /* add feature next to runs_after */
    1531         [ -  + ]:          5 :                 STAILQ_INSERT_AFTER(&arc->all_features, after_finfo, finfo, next_feature);
    1532                 :            :         } else {
    1533         [ +  + ]:         12 :                 if (before_finfo) {
    1534                 :            :                         /* add finfo before "before_finfo" element in the list */
    1535                 :            :                         after_finfo = NULL;
    1536         [ +  - ]:          3 :                         STAILQ_FOREACH(temp, &arc->all_features, next_feature) {
    1537         [ +  - ]:          3 :                                 if (before_finfo == temp) {
    1538         [ -  + ]:          3 :                                         if (after_finfo)
    1539         [ #  # ]:          0 :                                                 STAILQ_INSERT_AFTER(&arc->all_features, after_finfo,
    1540                 :            :                                                                     finfo, next_feature);
    1541                 :            :                                         else
    1542         [ -  + ]:          3 :                                                 STAILQ_INSERT_HEAD(&arc->all_features, finfo,
    1543                 :            :                                                                    next_feature);
    1544                 :            : 
    1545                 :            :                                         /* override node process fn */
    1546                 :          3 :                                         rc = node_override_process_func(finfo->feature_node_id,
    1547                 :            :                                                                         freg->feature_process_fn);
    1548                 :            : 
    1549         [ -  + ]:          3 :                                         if (rc < 0) {
    1550                 :          0 :                                                 graph_err("node_override_process_func failed for %s",
    1551                 :            :                                                           freg->feature_name);
    1552                 :          0 :                                                 goto finfo_free;
    1553                 :            :                                         }
    1554                 :            :                                         return 0;
    1555                 :            :                                 }
    1556                 :          0 :                                 after_finfo = temp;
    1557                 :            :                         }
    1558                 :            :                 } else {
    1559                 :            :                         /* Very first feature just needs to be added to list */
    1560                 :          9 :                         STAILQ_INSERT_TAIL(&arc->all_features, finfo, next_feature);
    1561                 :            :                 }
    1562                 :            :         }
    1563                 :            :         /* override node_process_fn */
    1564                 :         14 :         rc = node_override_process_func(finfo->feature_node_id, freg->feature_process_fn);
    1565         [ -  + ]:         14 :         if (rc < 0) {
    1566                 :          0 :                 graph_err("node_override_process_func failed for %s", freg->feature_name);
    1567                 :          0 :                 goto finfo_free;
    1568                 :            :         }
    1569                 :            : 
    1570         [ +  - ]:         14 :         if (freg->feature_node)
    1571                 :         14 :                 feat_dbg("arc-%s: feature %s node %s process() overridden with %p",
    1572                 :            :                           freg->arc_name, freg->feature_name, freg->feature_node->name,
    1573                 :            :                           freg->feature_process_fn);
    1574                 :            :         else
    1575                 :          0 :                 feat_dbg("arc-%s: feature %s nodeid %u process() overriding with %p",
    1576                 :            :                           freg->arc_name, freg->feature_name,
    1577                 :            :                           freg->feature_node_id, freg->feature_process_fn);
    1578                 :            : 
    1579                 :            :         return 0;
    1580                 :          0 : finfo_free:
    1581                 :          0 :         rte_free(finfo);
    1582                 :            : 
    1583                 :          0 :         return -1;
    1584                 :            : }
    1585                 :            : 
    1586                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_lookup, 25.07)
    1587                 :            : int
    1588                 :          0 : rte_graph_feature_lookup(rte_graph_feature_arc_t _arc, const char *feature_name,
    1589                 :            :                          rte_graph_feature_t *feat)
    1590                 :            : {
    1591         [ #  # ]:          0 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1592                 :          0 :         struct rte_graph_feature_node_list *finfo = NULL;
    1593                 :            :         uint32_t slot;
    1594                 :            : 
    1595         [ #  # ]:          0 :         if (!arc)
    1596                 :          0 :                 return -1;
    1597                 :            : 
    1598         [ #  # ]:          0 :         if (!nodeinfo_lkup_by_name(arc, feature_name, &finfo, &slot)) {
    1599                 :          0 :                 *feat = (rte_graph_feature_t) slot;
    1600                 :          0 :                 return 0;
    1601                 :            :         }
    1602                 :            : 
    1603                 :            :         return -1;
    1604                 :            : }
    1605                 :            : 
    1606                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_enable, 25.07)
    1607                 :            : int
    1608                 :        275 : rte_graph_feature_enable(rte_graph_feature_arc_t _arc, uint32_t index,
    1609                 :            :                          const char *feature_name, uint16_t app_cookie,
    1610                 :            :                          struct rte_rcu_qsbr *qsbr)
    1611                 :            : {
    1612         [ +  - ]:        275 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1613                 :        275 :         struct rte_graph_feature_node_list *finfo = NULL;
    1614                 :            :         struct rte_graph_feature_data *gfd = NULL;
    1615                 :            :         uint64_t bitmask;
    1616                 :            :         uint32_t slot;
    1617                 :            : 
    1618         [ -  + ]:        275 :         if (!arc) {
    1619                 :          0 :                 graph_err("Invalid feature arc: 0x%x", _arc);
    1620                 :          0 :                 return -1;
    1621                 :            :         }
    1622                 :            : 
    1623                 :        275 :         feat_dbg("%s: Enabling feature: %s for index: %u",
    1624                 :            :                  arc->feature_arc_name, feature_name, index);
    1625                 :            : 
    1626   [ +  +  +  - ]:        278 :         if ((!arc->runtime_enabled_features &&
    1627                 :          3 :             (prepare_feature_arc_before_first_enable(arc) < 0)))
    1628                 :            :                 return -1;
    1629                 :            : 
    1630         [ +  + ]:        275 :         if (feature_enable_disable_validate(_arc, index, feature_name, 1 /* enable */, true))
    1631                 :            :                 return -1;
    1632                 :            : 
    1633                 :            :         /** This should not fail as validate() has passed */
    1634         [ +  - ]:        272 :         if (nodeinfo_lkup_by_name(arc, feature_name, &finfo, &slot))
    1635                 :            :                 return -1;
    1636                 :            : 
    1637                 :        272 :         gfd = rte_graph_feature_data_get(arc, fdata_reserve(arc, slot, index));
    1638                 :            : 
    1639                 :            :         /* Set current app_cookie */
    1640                 :        272 :         rte_atomic_store_explicit(&gfd->app_cookie, app_cookie, rte_memory_order_relaxed);
    1641                 :            : 
    1642                 :            :         /* Set bitmask in control path bitmask */
    1643                 :        272 :         rte_bit_relaxed_set64(graph_uint_cast(slot), &arc->feature_bit_mask_by_index[index]);
    1644                 :            : 
    1645         [ +  - ]:        272 :         if (refill_fastpath_data(arc, slot, index, 1 /* enable */) < 0)
    1646                 :            :                 return -1;
    1647                 :            : 
    1648                 :            :         /* On very first feature enable instance */
    1649         [ +  + ]:        272 :         if (!finfo->ref_count) {
    1650                 :            :                 /* If first time feature getting enabled
    1651                 :            :                  */
    1652                 :          7 :                 bitmask = rte_atomic_load_explicit(&arc->fp_feature_enable_bitmask,
    1653                 :            :                                                    rte_memory_order_relaxed);
    1654                 :            : 
    1655                 :          7 :                 bitmask |= RTE_BIT64(slot);
    1656                 :            : 
    1657                 :          7 :                 rte_atomic_store_explicit(&arc->fp_feature_enable_bitmask,
    1658                 :            :                                           bitmask, rte_memory_order_relaxed);
    1659                 :            :         }
    1660                 :            : 
    1661                 :            :         /* Slow path updates */
    1662                 :        272 :         arc->runtime_enabled_features++;
    1663                 :            : 
    1664                 :            :         /* Increase feature node info reference count */
    1665                 :        272 :         finfo->ref_count++;
    1666                 :            : 
    1667                 :            :         /* Release extra fdata, if reserved before */
    1668                 :        272 :         extra_fdata_release(arc, slot, index);
    1669                 :            : 
    1670         [ -  + ]:        272 :         if (qsbr)
    1671                 :          0 :                 rte_rcu_qsbr_synchronize(qsbr, RTE_QSBR_THRID_INVALID);
    1672                 :            : 
    1673         [ +  - ]:        272 :         if (finfo->notifier_cb)
    1674                 :        272 :                 finfo->notifier_cb(arc->feature_arc_name, finfo->feature_name,
    1675                 :            :                                    finfo->feature_node_id, index,
    1676                 :        272 :                                    true /* enable */, gfd->app_cookie);
    1677                 :            : 
    1678                 :            :         return 0;
    1679                 :            : }
    1680                 :            : 
    1681                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_disable, 25.07)
    1682                 :            : int
    1683                 :        272 : rte_graph_feature_disable(rte_graph_feature_arc_t _arc, uint32_t index, const char *feature_name,
    1684                 :            :                           struct rte_rcu_qsbr *qsbr)
    1685                 :            : {
    1686         [ +  - ]:        272 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1687                 :            :         struct rte_graph_feature_data *gfd = NULL, *extra_gfd = NULL;
    1688                 :        272 :         struct rte_graph_feature_node_list *finfo = NULL;
    1689                 :            :         rte_graph_feature_data_t extra_fdata;
    1690                 :            :         uint32_t slot, last_end_feature;
    1691                 :            :         uint64_t bitmask;
    1692                 :            : 
    1693         [ -  + ]:        272 :         if (!arc) {
    1694                 :          0 :                 graph_err("Invalid feature arc: 0x%x", _arc);
    1695                 :          0 :                 return -1;
    1696                 :            :         }
    1697                 :        272 :         feat_dbg("%s: Disable feature: %s for index: %u",
    1698                 :            :                  arc->feature_arc_name, feature_name, index);
    1699                 :            : 
    1700         [ +  - ]:        272 :         if (feature_enable_disable_validate(_arc, index, feature_name, 0, true))
    1701                 :            :                 return -1;
    1702                 :            : 
    1703         [ +  - ]:        272 :         if (nodeinfo_lkup_by_name(arc, feature_name, &finfo, &slot))
    1704                 :            :                 return -1;
    1705                 :            : 
    1706         [ +  - ]:        272 :         last_end_feature = rte_fls_u64(arc->feature_bit_mask_by_index[index]);
    1707         [ -  + ]:        272 :         if (last_end_feature != arc->num_added_features) {
    1708                 :          0 :                 graph_err("%s/%s: No end feature enabled",
    1709                 :            :                           arc->feature_arc_name, feature_name);
    1710                 :          0 :                 return -1;
    1711                 :            :         }
    1712                 :            : 
    1713                 :            :         /* If feature is not last feature, unset in control plane bitmask */
    1714                 :        272 :         last_end_feature = arc->num_added_features - 1;
    1715         [ +  + ]:        272 :         if (slot != last_end_feature)
    1716                 :            :                 rte_bit_relaxed_clear64(graph_uint_cast(slot),
    1717                 :            :                                         &arc->feature_bit_mask_by_index[index]);
    1718                 :            : 
    1719                 :            :         /* we have allocated one extra feature data space. Get extra feature data
    1720                 :            :          * No need to reserve instead use fixed  extra data for an index
    1721                 :            :          */
    1722                 :        272 :         extra_fdata = extra_fdata_reserve(arc, slot, index);
    1723                 :            :         extra_gfd = rte_graph_feature_data_get(arc, extra_fdata);
    1724                 :            : 
    1725                 :            :         gfd = rte_graph_feature_data_get(arc, fdata_reserve(arc, slot, index));
    1726                 :            : 
    1727                 :            :         /*
    1728                 :            :          * Packets may have reached to feature node which is getting disabled.
    1729                 :            :          * We want to steer those packets to last feature node so that they can
    1730                 :            :          * exit arc
    1731                 :            :          * - First, reset next_edge of extra feature data to point to last_feature_node
    1732                 :            :          * - Secondly, reset next_feature_data of current feature getting disabled to extra
    1733                 :            :          *   feature data
    1734                 :            :          */
    1735                 :        272 :         rte_atomic_store_explicit(&extra_gfd->next_edge, finfo->edge_to_last_feature,
    1736                 :            :                                   rte_memory_order_relaxed);
    1737                 :        272 :         rte_atomic_store_explicit(&extra_gfd->next_feature_data, RTE_GRAPH_FEATURE_DATA_INVALID,
    1738                 :            :                                   rte_memory_order_relaxed);
    1739                 :        272 :         rte_atomic_store_explicit(&gfd->next_feature_data, extra_fdata,
    1740                 :            :                                   rte_memory_order_relaxed);
    1741                 :        272 :         rte_atomic_store_explicit(&gfd->next_edge, finfo->edge_to_last_feature,
    1742                 :            :                                   rte_memory_order_relaxed);
    1743                 :            : 
    1744                 :            :         /* Now we can unwire fast path*/
    1745         [ +  - ]:        272 :         if (refill_fastpath_data(arc, slot, index, 0 /* disable */) < 0)
    1746                 :            :                 return -1;
    1747                 :            : 
    1748                 :        272 :         finfo->ref_count--;
    1749                 :            : 
    1750                 :            :         /* When last feature is disabled */
    1751         [ +  + ]:        272 :         if (!finfo->ref_count) {
    1752                 :            :                 /* If no feature enabled, reset feature in u64 fast path bitmask */
    1753                 :          7 :                 bitmask = rte_atomic_load_explicit(&arc->fp_feature_enable_bitmask,
    1754                 :            :                                                    rte_memory_order_relaxed);
    1755                 :          7 :                 bitmask &= ~(RTE_BIT64(slot));
    1756                 :          7 :                 rte_atomic_store_explicit(&arc->fp_feature_enable_bitmask, bitmask,
    1757                 :            :                                           rte_memory_order_relaxed);
    1758                 :            :         }
    1759                 :            : 
    1760         [ -  + ]:        272 :         if (qsbr)
    1761                 :          0 :                 rte_rcu_qsbr_synchronize(qsbr, RTE_QSBR_THRID_INVALID);
    1762                 :            : 
    1763                 :            :         /* Call notifier cb with valid app_cookie */
    1764         [ +  - ]:        272 :         if (finfo->notifier_cb)
    1765                 :        272 :                 finfo->notifier_cb(arc->feature_arc_name, finfo->feature_name,
    1766                 :            :                                    finfo->feature_node_id, index,
    1767                 :        272 :                                    false /* disable */, gfd->app_cookie);
    1768                 :            : 
    1769                 :            :         /*
    1770                 :            :          * 1. Do not reset gfd for now as feature node might be in execution
    1771                 :            :          *
    1772                 :            :          * 2. We also don't call fdata_release() as that may return same
    1773                 :            :          * feature_data for other index for case like:
    1774                 :            :          *
    1775                 :            :          * feature_enable(arc, index-0, feature_name, cookie1);
    1776                 :            :          * feature_enable(arc, index-1, feature_name, cookie2);
    1777                 :            :          *
    1778                 :            :          * Second call can return same fdata which we avoided releasing here.
    1779                 :            :          * In order to make above case work, application has to mandatory use
    1780                 :            :          * RCU mechanism. For now fdata is not released until arc_destroy
    1781                 :            :          *
    1782                 :            :          * Only exception is
    1783                 :            :          * for(i=0; i< 100; i++) {
    1784                 :            :          *   feature_enable(arc, index-0, feature_name, cookie1);
    1785                 :            :          *   feature_disable(arc, index-0, feature_name, cookie1);
    1786                 :            :          * }
    1787                 :            :          * where RCU should be used but this is not valid use-case from control plane.
    1788                 :            :          * If it is valid use-case then provide RCU argument
    1789                 :            :          */
    1790                 :            : 
    1791                 :            :         /* Reset app_cookie later after calling notifier_cb */
    1792                 :        272 :         rte_atomic_store_explicit(&gfd->app_cookie, UINT16_MAX, rte_memory_order_relaxed);
    1793                 :            : 
    1794                 :        272 :         arc->runtime_enabled_features--;
    1795                 :            : 
    1796                 :        272 :         return 0;
    1797                 :            : }
    1798                 :            : 
    1799                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_destroy, 25.07)
    1800                 :            : int
    1801                 :          9 : rte_graph_feature_arc_destroy(rte_graph_feature_arc_t _arc)
    1802                 :            : {
    1803         [ +  - ]:          9 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1804                 :            :         rte_graph_feature_arc_main_t *dm = __rte_graph_feature_arc_main;
    1805                 :            :         struct rte_graph_feature_node_list *node_info = NULL;
    1806                 :            :         struct rte_graph_feature_data *fdptr = NULL;
    1807                 :            :         rte_graph_feature_data_t fdata;
    1808                 :            :         int iter;
    1809                 :            : 
    1810         [ -  + ]:          9 :         if (!arc) {
    1811                 :          0 :                 graph_err("Invalid feature arc: 0x%x", _arc);
    1812                 :          0 :                 return -1;
    1813                 :            :         }
    1814                 :            : 
    1815         [ +  + ]:         26 :         while (!STAILQ_EMPTY(&arc->all_features)) {
    1816                 :            :                 node_info = STAILQ_FIRST(&arc->all_features);
    1817         [ +  + ]:         17 :                 STAILQ_REMOVE_HEAD(&arc->all_features, next_feature);
    1818                 :            :                 /* Notify application */
    1819         [ +  + ]:         17 :                 if (node_info->notifier_cb) {
    1820         [ +  + ]:       2107 :                         for (iter = 0; iter < arc->max_indexes; iter++) {
    1821                 :            :                                 /* If feature is not enabled on this index, skip */
    1822                 :       3920 :                                 if (!(arc->feature_bit_mask_by_index[iter] &
    1823         [ +  + ]:       2096 :                                     RTE_BIT64(node_info->finfo_index)))
    1824                 :       1824 :                                         continue;
    1825                 :            : 
    1826                 :            :                                 /* fdata_reserve would return already allocated
    1827                 :            :                                  * fdata for [finfo_index, iter]
    1828                 :            :                                  */
    1829                 :        272 :                                 fdata = fdata_reserve(arc, node_info->finfo_index, iter);
    1830         [ +  - ]:        272 :                                 if (fdata != RTE_GRAPH_FEATURE_DATA_INVALID) {
    1831                 :            :                                         fdptr = rte_graph_feature_data_get(arc, fdata);
    1832                 :        272 :                                         node_info->notifier_cb(arc->feature_arc_name,
    1833                 :        272 :                                                                node_info->feature_name,
    1834                 :            :                                                                node_info->feature_node_id,
    1835                 :            :                                                                iter, false /* disable */,
    1836                 :        272 :                                                                fdptr->app_cookie);
    1837                 :            :                                 } else {
    1838                 :          0 :                                         node_info->notifier_cb(arc->feature_arc_name,
    1839                 :          0 :                                                                node_info->feature_name,
    1840                 :            :                                                                node_info->feature_node_id,
    1841                 :            :                                                                iter, false /* disable */,
    1842                 :            :                                                                UINT16_MAX /* invalid cookie */);
    1843                 :            :                                 }
    1844                 :            :                                 /* fdata_release() is not used yet, use it for sake
    1845                 :            :                                  * of function unused warnings
    1846                 :            :                                  */
    1847                 :        272 :                                 fdata = fdata_release(arc, node_info->finfo_index, iter);
    1848                 :            :                         }
    1849                 :            :                 }
    1850                 :         17 :                 rte_free(node_info);
    1851                 :            :         }
    1852                 :            : 
    1853                 :          9 :         dm->feature_arcs[arc->feature_arc_index] = GRAPH_FEATURE_ARC_PTR_INITIALIZER;
    1854                 :            : 
    1855                 :          9 :         rte_free(arc->feature_data_by_index);
    1856                 :            : 
    1857                 :          9 :         rte_free(arc->feature_bit_mask_by_index);
    1858                 :            : 
    1859                 :          9 :         rte_memzone_free(rte_memzone_lookup(arc->feature_arc_name));
    1860                 :            : 
    1861                 :          9 :         return 0;
    1862                 :            : }
    1863                 :            : 
    1864                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_cleanup, 25.07)
    1865                 :            : int
    1866                 :          2 : rte_graph_feature_arc_cleanup(void)
    1867                 :            : {
    1868                 :          2 :         rte_graph_feature_arc_main_t *dm = __rte_graph_feature_arc_main;
    1869                 :            :         struct rte_graph_feature_arc *arc = NULL;
    1870                 :            :         uint32_t iter;
    1871                 :            : 
    1872         [ +  - ]:          2 :         if (!__rte_graph_feature_arc_main)
    1873                 :            :                 return -1;
    1874                 :            : 
    1875         [ +  + ]:         25 :         for (iter = 0; iter < dm->max_feature_arcs; iter++) {
    1876         [ +  - ]:         23 :                 arc = rte_graph_feature_arc_get(iter);
    1877                 :            : 
    1878         [ -  + ]:          7 :                 if (!arc)
    1879                 :         16 :                         continue;
    1880                 :            : 
    1881                 :          7 :                 rte_graph_feature_arc_destroy(arc->feature_arc_index);
    1882                 :            :         }
    1883                 :          2 :         rte_memzone_free(rte_memzone_lookup(FEATURE_ARC_MEMZONE_NAME));
    1884                 :          2 :         __rte_graph_feature_arc_main = NULL;
    1885                 :            : 
    1886                 :          2 :         return 0;
    1887                 :            : }
    1888                 :            : 
    1889                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_lookup_by_name, 25.07)
    1890                 :            : int
    1891                 :         60 : rte_graph_feature_arc_lookup_by_name(const char *arc_name, rte_graph_feature_arc_t *_arc)
    1892                 :            : {
    1893                 :            :         struct rte_graph_feature_arc *arc = NULL;
    1894                 :            :         const struct rte_memzone *mz = NULL;
    1895                 :            :         rte_graph_feature_arc_main_t *dm;
    1896                 :            :         uint32_t iter;
    1897                 :            : 
    1898         [ +  + ]:         60 :         if (_arc)
    1899                 :         59 :                 *_arc = RTE_GRAPH_FEATURE_ARC_INITIALIZER;
    1900                 :            : 
    1901         [ -  + ]:         60 :         if (!__rte_graph_feature_arc_main) {
    1902                 :          0 :                 mz = rte_memzone_lookup(FEATURE_ARC_MEMZONE_NAME);
    1903         [ #  # ]:          0 :                 if (mz)
    1904                 :          0 :                         __rte_graph_feature_arc_main = mz->addr;
    1905                 :            :                 else
    1906                 :            :                         return -1;
    1907                 :            :         }
    1908                 :            : 
    1909                 :         60 :         dm = __rte_graph_feature_arc_main;
    1910                 :            : 
    1911         [ +  + ]:        137 :         for (iter = 0; iter < dm->max_feature_arcs; iter++) {
    1912         [ +  - ]:        136 :                 arc = rte_graph_feature_arc_get(iter);
    1913         [ -  + ]:        129 :                 if (!arc)
    1914                 :          7 :                         continue;
    1915                 :            : 
    1916         [ +  + ]:        129 :                 if ((strstr(arc->feature_arc_name, arc_name)) &&
    1917         [ +  - ]:         59 :                     (strlen(arc->feature_arc_name) == strlen(arc_name))) {
    1918         [ +  - ]:         59 :                         if (_arc)
    1919                 :         59 :                                 *_arc = arc->feature_arc_index;
    1920                 :         59 :                         return 0;
    1921                 :            :                 }
    1922                 :            :         }
    1923                 :            : 
    1924                 :            :         return -1;
    1925                 :            : }
    1926                 :            : 
    1927                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_num_enabled_features, 25.07)
    1928                 :            : uint32_t
    1929                 :         17 : rte_graph_feature_arc_num_enabled_features(rte_graph_feature_arc_t _arc)
    1930                 :            : {
    1931         [ +  - ]:         17 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1932                 :            : 
    1933         [ -  + ]:         17 :         if (!arc) {
    1934                 :          0 :                 graph_err("Invalid feature arc: 0x%x", _arc);
    1935                 :          0 :                 return 0;
    1936                 :            :         }
    1937                 :            : 
    1938                 :         17 :         return arc->runtime_enabled_features;
    1939                 :            : }
    1940                 :            : 
    1941                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_num_features, 25.07)
    1942                 :            : uint32_t
    1943                 :        574 : rte_graph_feature_arc_num_features(rte_graph_feature_arc_t _arc)
    1944                 :            : {
    1945         [ +  - ]:        574 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1946                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
    1947                 :            :         uint32_t count = 0;
    1948                 :            : 
    1949         [ -  + ]:        574 :         if (!arc) {
    1950                 :          0 :                 graph_err("Invalid feature arc: 0x%x", _arc);
    1951                 :          0 :                 return 0;
    1952                 :            :         }
    1953                 :            : 
    1954         [ +  + ]:       2772 :         STAILQ_FOREACH(finfo, &arc->all_features, next_feature)
    1955                 :       2198 :                 count++;
    1956                 :            : 
    1957                 :            :         return count;
    1958                 :            : }
    1959                 :            : 
    1960                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_feature_to_name, 25.07)
    1961                 :            : char *
    1962                 :        554 : rte_graph_feature_arc_feature_to_name(rte_graph_feature_arc_t _arc, rte_graph_feature_t feat)
    1963                 :            : {
    1964         [ +  - ]:        554 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1965                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
    1966                 :        554 :         uint32_t slot = feat;
    1967                 :            : 
    1968         [ +  - ]:        554 :         if (!arc)
    1969                 :            :                 return NULL;
    1970                 :            : 
    1971         [ -  + ]:        554 :         if (feat >= rte_graph_feature_arc_num_features(_arc)) {
    1972                 :          0 :                 graph_err("%s: feature %u does not exist", arc->feature_arc_name, feat);
    1973                 :          0 :                 return NULL;
    1974                 :            :         }
    1975                 :            :         if (!nodeinfo_lkup_by_index(arc, slot, &finfo, 0/* ignore sanity*/))
    1976                 :        554 :                 return finfo->feature_name;
    1977                 :            : 
    1978                 :            :         return NULL;
    1979                 :            : }
    1980                 :            : 
    1981                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_feature_to_node, 25.07)
    1982                 :            : int
    1983                 :          0 : rte_graph_feature_arc_feature_to_node(rte_graph_feature_arc_t _arc, rte_graph_feature_t feat,
    1984                 :            :                                       rte_node_t *node)
    1985                 :            : {
    1986         [ #  # ]:          0 :         struct rte_graph_feature_arc *arc = rte_graph_feature_arc_get(_arc);
    1987                 :            :         struct rte_graph_feature_node_list *finfo = NULL;
    1988                 :          0 :         uint32_t slot = feat;
    1989                 :            : 
    1990         [ #  # ]:          0 :         if (!arc)
    1991                 :            :                 return -1;
    1992                 :            : 
    1993         [ #  # ]:          0 :         if (node)
    1994                 :          0 :                 *node = RTE_NODE_ID_INVALID;
    1995                 :            : 
    1996         [ #  # ]:          0 :         if (feat >= rte_graph_feature_arc_num_features(_arc)) {
    1997                 :          0 :                 graph_err("%s: feature %u does not exist", arc->feature_arc_name, feat);
    1998                 :          0 :                 return -1;
    1999                 :            :         }
    2000                 :            :         if (!nodeinfo_lkup_by_index(arc, slot, &finfo, 0/* ignore sanity*/)) {
    2001         [ #  # ]:          0 :                 if (node)
    2002                 :          0 :                         *node = finfo->feature_node_id;
    2003                 :          0 :                 return 0;
    2004                 :            :         }
    2005                 :            :         return -1;
    2006                 :            : }
    2007                 :            : 
    2008                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(__rte_graph_feature_arc_register, 25.07)
    2009                 :       2277 : void __rte_graph_feature_arc_register(struct rte_graph_feature_arc_register *reg,
    2010                 :            :                                       const char *caller_name, int lineno)
    2011                 :            : {
    2012                 :            :         RTE_SET_USED(caller_name);
    2013                 :            :         RTE_SET_USED(lineno);
    2014                 :            :         /* Do not validate arc registration here but as part of rte_graph_feature_arc_init() */
    2015                 :       2277 :         STAILQ_INSERT_TAIL(&feature_arc_list, reg, next_arc);
    2016                 :       2277 : }
    2017                 :            : 
    2018                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(__rte_graph_feature_register, 25.07)
    2019                 :       1012 : void __rte_graph_feature_register(struct rte_graph_feature_register *reg,
    2020                 :            :                                   const char *caller_name, int lineno)
    2021                 :            : {
    2022         [ +  - ]:       1012 :         if (feature_registration_validate(reg, caller_name, lineno, 0, 0, true) < 0)
    2023                 :            :                 return;
    2024                 :            : 
    2025                 :            :         /* Add to the feature_list*/
    2026                 :       1012 :         STAILQ_INSERT_TAIL(&feature_list, reg, next_feature);
    2027                 :            : }
    2028                 :            : 
    2029                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_graph_feature_arc_names_get, 25.07)
    2030                 :            : uint32_t
    2031                 :          0 : rte_graph_feature_arc_names_get(char *arc_names[])
    2032                 :            : {
    2033                 :          0 :         rte_graph_feature_arc_main_t *dm = __rte_graph_feature_arc_main;
    2034                 :            :         struct rte_graph_feature_arc *arc = NULL;
    2035                 :            :         uint32_t count, num_arcs;
    2036                 :            : 
    2037         [ #  # ]:          0 :         if (!__rte_graph_feature_arc_main)
    2038                 :            :                 return 0;
    2039                 :            : 
    2040         [ #  # ]:          0 :         for (count = 0, num_arcs = 0; count < dm->max_feature_arcs; count++)
    2041         [ #  # ]:          0 :                 if (dm->feature_arcs[count] != GRAPH_FEATURE_ARC_PTR_INITIALIZER)
    2042                 :          0 :                         num_arcs++;
    2043                 :            : 
    2044         [ #  # ]:          0 :         if (!num_arcs)
    2045                 :            :                 return 0;
    2046                 :            : 
    2047         [ #  # ]:          0 :         if (!arc_names)
    2048                 :          0 :                 return sizeof(char *) * num_arcs;
    2049                 :            : 
    2050         [ #  # ]:          0 :         for (count = 0, num_arcs = 0; count < dm->max_feature_arcs; count++) {
    2051         [ #  # ]:          0 :                 if (dm->feature_arcs[count] != GRAPH_FEATURE_ARC_PTR_INITIALIZER) {
    2052         [ #  # ]:          0 :                         arc = rte_graph_feature_arc_get(count);
    2053                 :          0 :                         arc_names[num_arcs] = arc->feature_arc_name;
    2054                 :          0 :                         num_arcs++;
    2055                 :            :                 }
    2056                 :            :         }
    2057                 :            :         return num_arcs;
    2058                 :            : }

Generated by: LCOV version 1.14