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 : : }
|