Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020 Intel Corporation
3 : : */
4 : : #include <errno.h>
5 : : #include <stdlib.h>
6 : : #include <string.h>
7 : : #include <stdio.h>
8 : : #include <sys/queue.h>
9 : : #include <unistd.h>
10 : :
11 : : #include <eal_export.h>
12 : : #include <rte_common.h>
13 : : #include <rte_byteorder.h>
14 : : #include <rte_tailq.h>
15 : : #include <rte_eal_memconfig.h>
16 : :
17 : : #include <rte_swx_table_selector.h>
18 : :
19 : : #include "rte_swx_ctl.h"
20 : :
21 : : #define CHECK(condition, err_code) \
22 : : do { \
23 : : if (!(condition)) \
24 : : return -(err_code); \
25 : : } while (0)
26 : :
27 : : #define ntoh64(x) rte_be_to_cpu_64(x)
28 : : #define hton64(x) rte_cpu_to_be_64(x)
29 : :
30 : : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
31 : : #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
32 : : #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
33 : : #else
34 : : #define field_ntoh(val, n_bits) (val)
35 : : #define field_hton(val, n_bits) (val)
36 : : #endif
37 : :
38 : : struct action {
39 : : struct rte_swx_ctl_action_info info;
40 : : struct rte_swx_ctl_action_arg_info *args;
41 : : uint32_t data_size;
42 : : };
43 : :
44 : : struct table {
45 : : struct rte_swx_ctl_table_info info;
46 : : struct rte_swx_ctl_table_match_field_info *mf;
47 : :
48 : : /* Match field with the smallest offset. */
49 : : struct rte_swx_ctl_table_match_field_info *mf_first;
50 : :
51 : : /* Match field with the biggest offset. */
52 : : struct rte_swx_ctl_table_match_field_info *mf_last;
53 : :
54 : : struct rte_swx_ctl_table_action_info *actions;
55 : : struct rte_swx_table_ops ops;
56 : : struct rte_swx_table_params params;
57 : :
58 : : /* Set of "stable" keys: these keys are currently part of the table;
59 : : * these keys will be preserved with no action data changes after the
60 : : * next commit.
61 : : */
62 : : struct rte_swx_table_entry_list entries;
63 : :
64 : : /* Set of new keys: these keys are currently NOT part of the table;
65 : : * these keys will be added to the table on the next commit, if
66 : : * the commit operation is successful.
67 : : */
68 : : struct rte_swx_table_entry_list pending_add;
69 : :
70 : : /* Set of keys to be modified: these keys are currently part of the
71 : : * table; these keys are still going to be part of the table after the
72 : : * next commit, but their action data will be modified if the commit
73 : : * operation is successful. The modify0 list contains the keys with the
74 : : * current action data, the modify1 list contains the keys with the
75 : : * modified action data.
76 : : */
77 : : struct rte_swx_table_entry_list pending_modify0;
78 : : struct rte_swx_table_entry_list pending_modify1;
79 : :
80 : : /* Set of keys to be deleted: these keys are currently part of the
81 : : * table; these keys are to be deleted from the table on the next
82 : : * commit, if the commit operation is successful.
83 : : */
84 : : struct rte_swx_table_entry_list pending_delete;
85 : :
86 : : /* The pending default action: this is NOT the current default action;
87 : : * this will be the new default action after the next commit, if the
88 : : * next commit operation is successful.
89 : : */
90 : : struct rte_swx_table_entry *pending_default;
91 : :
92 : : int is_stub;
93 : : uint32_t n_add;
94 : : uint32_t n_modify;
95 : : uint32_t n_delete;
96 : : };
97 : :
98 : : struct selector {
99 : : /* Selector table info. */
100 : : struct rte_swx_ctl_selector_info info;
101 : :
102 : : /* group_id field. */
103 : : struct rte_swx_ctl_table_match_field_info group_id_field;
104 : :
105 : : /* selector fields. */
106 : : struct rte_swx_ctl_table_match_field_info *selector_fields;
107 : :
108 : : /* member_id field. */
109 : : struct rte_swx_ctl_table_match_field_info member_id_field;
110 : :
111 : : /* Current selector table. Array of info.n_groups_max elements.*/
112 : : struct rte_swx_table_selector_group **groups;
113 : :
114 : : /* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
115 : : */
116 : : struct rte_swx_table_selector_group **pending_groups;
117 : :
118 : : /* Valid flag per group. Array of n_groups_max elements. */
119 : : int *groups_added;
120 : :
121 : : /* Pending delete flag per group. Group deletion is subject to the next commit. Array of
122 : : * info.n_groups_max elements.
123 : : */
124 : : int *groups_pending_delete;
125 : :
126 : : /* Params. */
127 : : struct rte_swx_table_selector_params params;
128 : : };
129 : :
130 : : struct learner {
131 : : struct rte_swx_ctl_learner_info info;
132 : : struct rte_swx_ctl_table_match_field_info *mf;
133 : : struct rte_swx_ctl_table_action_info *actions;
134 : : uint32_t action_data_size;
135 : :
136 : : /* The pending default action: this is NOT the current default action;
137 : : * this will be the new default action after the next commit, if the
138 : : * next commit operation is successful.
139 : : */
140 : : struct rte_swx_table_entry *pending_default;
141 : : };
142 : :
143 : : struct rte_swx_ctl_pipeline {
144 : : struct rte_swx_ctl_pipeline_info info;
145 : : struct rte_swx_pipeline *p;
146 : : struct action *actions;
147 : : struct table *tables;
148 : : struct selector *selectors;
149 : : struct learner *learners;
150 : : struct rte_swx_table_state *ts;
151 : : struct rte_swx_table_state *ts_next;
152 : : int numa_node;
153 : : };
154 : :
155 : : static struct action *
156 : 0 : action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
157 : : {
158 : : uint32_t i;
159 : :
160 [ # # ]: 0 : for (i = 0; i < ctl->info.n_actions; i++) {
161 : 0 : struct action *a = &ctl->actions[i];
162 : :
163 [ # # ]: 0 : if (!strcmp(action_name, a->info.name))
164 : 0 : return a;
165 : : }
166 : :
167 : : return NULL;
168 : : }
169 : :
170 : : static void
171 : 0 : action_free(struct rte_swx_ctl_pipeline *ctl)
172 : : {
173 : : uint32_t i;
174 : :
175 [ # # ]: 0 : if (!ctl->actions)
176 : : return;
177 : :
178 [ # # ]: 0 : for (i = 0; i < ctl->info.n_actions; i++) {
179 : 0 : struct action *action = &ctl->actions[i];
180 : :
181 : 0 : free(action->args);
182 : : }
183 : :
184 : 0 : free(ctl->actions);
185 : 0 : ctl->actions = NULL;
186 : : }
187 : :
188 : : static struct table *
189 : 0 : table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
190 : : {
191 : : uint32_t i;
192 : :
193 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
194 : 0 : struct table *table = &ctl->tables[i];
195 : :
196 [ # # ]: 0 : if (!strcmp(table_name, table->info.name))
197 : 0 : return table;
198 : : }
199 : :
200 : : return NULL;
201 : : }
202 : :
203 : : static int
204 : 0 : table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
205 : : {
206 : 0 : struct table *table = &ctl->tables[table_id];
207 : : struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
208 : : uint8_t *key_mask = NULL;
209 : : enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
210 : : uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
211 : :
212 [ # # ]: 0 : if (table->info.n_match_fields) {
213 : : uint32_t n_match_fields_em = 0;
214 : :
215 : : /* Find first (smallest offset) and last (biggest offset) match fields. */
216 : 0 : first = &table->mf[0];
217 : : last = &table->mf[0];
218 : :
219 [ # # ]: 0 : for (i = 1; i < table->info.n_match_fields; i++) {
220 : 0 : struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
221 : :
222 [ # # ]: 0 : if (f->offset < first->offset)
223 : : first = f;
224 : :
225 [ # # ]: 0 : if (f->offset > last->offset)
226 : : last = f;
227 : : }
228 : :
229 : : /* match_type. */
230 [ # # ]: 0 : for (i = 0; i < table->info.n_match_fields; i++) {
231 : 0 : struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
232 : :
233 [ # # ]: 0 : if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
234 : 0 : n_match_fields_em++;
235 : : }
236 : :
237 [ # # ]: 0 : if (n_match_fields_em == table->info.n_match_fields)
238 : : match_type = RTE_SWX_TABLE_MATCH_EXACT;
239 : :
240 : : /* key_offset. */
241 : 0 : key_offset = first->offset / 8;
242 : :
243 : : /* key_size. */
244 : 0 : key_size = (last->offset + last->n_bits - first->offset) / 8;
245 : :
246 : : /* key_mask. */
247 : 0 : key_mask = calloc(1, key_size);
248 [ # # ]: 0 : CHECK(key_mask, ENOMEM);
249 : :
250 [ # # ]: 0 : for (i = 0; i < table->info.n_match_fields; i++) {
251 : 0 : struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
252 : : uint32_t start;
253 : : size_t size;
254 : :
255 : 0 : start = (f->offset - first->offset) / 8;
256 : 0 : size = f->n_bits / 8;
257 : :
258 : 0 : memset(&key_mask[start], 0xFF, size);
259 : : }
260 : : }
261 : :
262 : : /* action_data_size. */
263 [ # # ]: 0 : for (i = 0; i < table->info.n_actions; i++) {
264 : 0 : uint32_t action_id = table->actions[i].action_id;
265 : 0 : struct action *a = &ctl->actions[action_id];
266 : :
267 : 0 : if (a->data_size > action_data_size)
268 : : action_data_size = a->data_size;
269 : : }
270 : :
271 : : /* Fill in. */
272 : 0 : table->params.match_type = match_type;
273 : 0 : table->params.key_size = key_size;
274 : 0 : table->params.key_offset = key_offset;
275 : 0 : table->params.key_mask0 = key_mask;
276 : 0 : table->params.action_data_size = action_data_size;
277 : 0 : table->params.hash_func = table->info.hash_func;
278 : 0 : table->params.n_keys_max = table->info.size;
279 : :
280 : 0 : table->mf_first = first;
281 : 0 : table->mf_last = last;
282 : :
283 : 0 : return 0;
284 : : }
285 : :
286 : : static void
287 : 0 : table_entry_free(struct rte_swx_table_entry *entry)
288 : : {
289 [ # # ]: 0 : if (!entry)
290 : : return;
291 : :
292 : 0 : free(entry->key);
293 : 0 : free(entry->key_mask);
294 : 0 : free(entry->action_data);
295 : 0 : free(entry);
296 : : }
297 : :
298 : : static struct rte_swx_table_entry *
299 : 0 : table_entry_alloc(struct table *table)
300 : : {
301 : : struct rte_swx_table_entry *entry;
302 : :
303 : 0 : entry = calloc(1, sizeof(struct rte_swx_table_entry));
304 [ # # ]: 0 : if (!entry)
305 : 0 : goto error;
306 : :
307 : : /* key, key_mask. */
308 [ # # ]: 0 : if (!table->is_stub) {
309 : 0 : entry->key = calloc(1, table->params.key_size);
310 [ # # ]: 0 : if (!entry->key)
311 : 0 : goto error;
312 : :
313 [ # # ]: 0 : if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
314 : 0 : entry->key_mask = calloc(1, table->params.key_size);
315 [ # # ]: 0 : if (!entry->key_mask)
316 : 0 : goto error;
317 : : }
318 : : }
319 : :
320 : : /* action_data. */
321 [ # # ]: 0 : if (table->params.action_data_size) {
322 : 0 : entry->action_data = calloc(1, table->params.action_data_size);
323 [ # # ]: 0 : if (!entry->action_data)
324 : 0 : goto error;
325 : : }
326 : :
327 : : return entry;
328 : :
329 : 0 : error:
330 : 0 : table_entry_free(entry);
331 : 0 : return NULL;
332 : : }
333 : :
334 : : static int
335 : : table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
336 : : {
337 : 0 : uint8_t *key_mask0 = table->params.key_mask0;
338 : 0 : uint32_t key_size = table->params.key_size, i;
339 : :
340 [ # # ]: 0 : if (!entry->key_mask)
341 : : return 0;
342 : :
343 [ # # ]: 0 : for (i = 0; i < key_size; i++) {
344 : 0 : uint8_t km0 = key_mask0[i];
345 : 0 : uint8_t km = entry->key_mask[i];
346 : :
347 [ # # ]: 0 : if ((km & km0) != km0)
348 : : return -EINVAL;
349 : : }
350 : :
351 : : return 0;
352 : : }
353 : :
354 : : static int
355 : 0 : table_entry_check(struct rte_swx_ctl_pipeline *ctl,
356 : : uint32_t table_id,
357 : : struct rte_swx_table_entry *entry,
358 : : int key_check,
359 : : int data_check)
360 : : {
361 : 0 : struct table *table = &ctl->tables[table_id];
362 : : int status;
363 : :
364 [ # # ]: 0 : CHECK(entry, EINVAL);
365 : :
366 [ # # # # ]: 0 : if (key_check && !table->is_stub) {
367 : : /* key. */
368 [ # # ]: 0 : CHECK(entry->key, EINVAL);
369 : :
370 : : /* key_mask. */
371 [ # # ]: 0 : if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
372 : : status = table_entry_key_check_em(table, entry);
373 [ # # ]: 0 : if (status)
374 : : return status;
375 : : }
376 : : }
377 : :
378 [ # # ]: 0 : if (data_check) {
379 : : struct action *a;
380 : : struct rte_swx_ctl_table_action_info *tai;
381 : : uint32_t i;
382 : :
383 : : /* action_id. */
384 [ # # ]: 0 : for (i = 0; i < table->info.n_actions; i++) {
385 : 0 : tai = &table->actions[i];
386 : :
387 [ # # ]: 0 : if (entry->action_id == tai->action_id)
388 : : break;
389 : : }
390 : :
391 [ # # ]: 0 : CHECK(i < table->info.n_actions, EINVAL);
392 : :
393 : : /* action_data. */
394 : 0 : a = &ctl->actions[entry->action_id];
395 [ # # # # ]: 0 : CHECK(!(a->data_size && !entry->action_data), EINVAL);
396 : :
397 : : /* When both key_check and data_check are true, we are interested in both the entry
398 : : * key and data, which means the operation is _regular_ table entry add.
399 : : */
400 [ # # # # ]: 0 : if (key_check && !tai->action_is_for_table_entries)
401 : : return -EINVAL;
402 : :
403 : : /* When key_check is false while data_check is true, we are only interested in the
404 : : * entry data, which means the operation is _default_ table entry add.
405 : : */
406 [ # # # # ]: 0 : if (!key_check && !tai->action_is_for_default_entry)
407 : 0 : return -EINVAL;
408 : : }
409 : :
410 : : return 0;
411 : : }
412 : :
413 : : static struct rte_swx_table_entry *
414 : 0 : table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
415 : : uint32_t table_id,
416 : : struct rte_swx_table_entry *entry,
417 : : int key_duplicate,
418 : : int data_duplicate)
419 : : {
420 : 0 : struct table *table = &ctl->tables[table_id];
421 : : struct rte_swx_table_entry *new_entry = NULL;
422 : :
423 [ # # ]: 0 : if (!entry)
424 : 0 : goto error;
425 : :
426 : 0 : new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
427 [ # # ]: 0 : if (!new_entry)
428 : 0 : goto error;
429 : :
430 [ # # # # ]: 0 : if (key_duplicate && !table->is_stub) {
431 : : /* key. */
432 [ # # ]: 0 : if (!entry->key)
433 : 0 : goto error;
434 : :
435 : 0 : new_entry->key = malloc(table->params.key_size);
436 [ # # ]: 0 : if (!new_entry->key)
437 : 0 : goto error;
438 : :
439 : : memcpy(new_entry->key, entry->key, table->params.key_size);
440 : :
441 : : /* key_signature. */
442 : 0 : new_entry->key_signature = entry->key_signature;
443 : :
444 : : /* key_mask. */
445 [ # # ]: 0 : if (entry->key_mask) {
446 : 0 : new_entry->key_mask = malloc(table->params.key_size);
447 [ # # ]: 0 : if (!new_entry->key_mask)
448 : 0 : goto error;
449 : :
450 : : memcpy(new_entry->key_mask,
451 : : entry->key_mask,
452 : : table->params.key_size);
453 : : }
454 : :
455 : : /* key_priority. */
456 : 0 : new_entry->key_priority = entry->key_priority;
457 : : }
458 : :
459 [ # # ]: 0 : if (data_duplicate) {
460 : : struct action *a;
461 : : uint32_t i;
462 : :
463 : : /* action_id. */
464 [ # # ]: 0 : for (i = 0; i < table->info.n_actions; i++)
465 [ # # ]: 0 : if (entry->action_id == table->actions[i].action_id)
466 : : break;
467 : :
468 [ # # ]: 0 : if (i >= table->info.n_actions)
469 : 0 : goto error;
470 : :
471 : 0 : new_entry->action_id = entry->action_id;
472 : :
473 : : /* action_data. */
474 : 0 : a = &ctl->actions[entry->action_id];
475 [ # # # # ]: 0 : if (a->data_size && !entry->action_data)
476 : 0 : goto error;
477 : :
478 : : /* The table layer provisions a constant action data size per
479 : : * entry, which should be the largest data size for all the
480 : : * actions enabled for the current table, and attempts to copy
481 : : * this many bytes each time a table entry is added, even if the
482 : : * specific action requires less data or even no data at all,
483 : : * hence we always have to allocate the max.
484 : : */
485 : 0 : new_entry->action_data = calloc(1, table->params.action_data_size);
486 [ # # ]: 0 : if (!new_entry->action_data)
487 : 0 : goto error;
488 : :
489 [ # # ]: 0 : if (a->data_size)
490 : 0 : memcpy(new_entry->action_data,
491 : 0 : entry->action_data,
492 : : a->data_size);
493 : : }
494 : :
495 : : return new_entry;
496 : :
497 : 0 : error:
498 : 0 : table_entry_free(new_entry);
499 : 0 : return NULL;
500 : : }
501 : :
502 : : static int
503 : 0 : table_entry_keycmp(struct table *table,
504 : : struct rte_swx_table_entry *e0,
505 : : struct rte_swx_table_entry *e1)
506 : : {
507 : 0 : uint32_t key_size = table->params.key_size;
508 : : uint32_t i;
509 : :
510 [ # # ]: 0 : for (i = 0; i < key_size; i++) {
511 : 0 : uint8_t *key_mask0 = table->params.key_mask0;
512 : : uint8_t km0, km[2], k[2];
513 : :
514 [ # # ]: 0 : km0 = key_mask0 ? key_mask0[i] : 0xFF;
515 : :
516 [ # # ]: 0 : km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
517 [ # # ]: 0 : km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
518 : :
519 : 0 : k[0] = e0->key[i];
520 : 0 : k[1] = e1->key[i];
521 : :
522 : : /* Mask comparison. */
523 [ # # ]: 0 : if ((km[0] & km0) != (km[1] & km0))
524 : : return 1; /* Not equal. */
525 : :
526 : : /* Value comparison. */
527 [ # # ]: 0 : if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
528 : : return 1; /* Not equal. */
529 : : }
530 : :
531 : : return 0; /* Equal. */
532 : : }
533 : :
534 : : static struct rte_swx_table_entry *
535 : : table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
536 : : {
537 : : struct rte_swx_table_entry *e;
538 : :
539 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->entries, node)
540 [ # # # # ]: 0 : if (!table_entry_keycmp(table, entry, e))
541 : : return e; /* Found. */
542 : :
543 : : return NULL; /* Not found. */
544 : : }
545 : :
546 : : static void
547 : 0 : table_entries_free(struct table *table)
548 : : {
549 : 0 : for ( ; ; ) {
550 : : struct rte_swx_table_entry *entry;
551 : :
552 : 0 : entry = TAILQ_FIRST(&table->entries);
553 [ # # ]: 0 : if (!entry)
554 : : break;
555 : :
556 [ # # ]: 0 : TAILQ_REMOVE(&table->entries, entry, node);
557 : 0 : table_entry_free(entry);
558 : : }
559 : 0 : }
560 : :
561 : : static struct rte_swx_table_entry *
562 : : table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
563 : : {
564 : : struct rte_swx_table_entry *e;
565 : :
566 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->pending_add, node)
567 [ # # # # ]: 0 : if (!table_entry_keycmp(table, entry, e))
568 : : return e; /* Found. */
569 : :
570 : : return NULL; /* Not found. */
571 : : }
572 : :
573 : : static void
574 : : table_pending_add_admit(struct table *table)
575 : : {
576 : 0 : TAILQ_CONCAT(&table->entries, &table->pending_add, node);
577 : : }
578 : :
579 : : static void
580 : 0 : table_pending_add_free(struct table *table)
581 : : {
582 : 0 : for ( ; ; ) {
583 : : struct rte_swx_table_entry *entry;
584 : :
585 : 0 : entry = TAILQ_FIRST(&table->pending_add);
586 [ # # ]: 0 : if (!entry)
587 : : break;
588 : :
589 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_add, entry, node);
590 : 0 : table_entry_free(entry);
591 : : }
592 : 0 : }
593 : :
594 : : static struct rte_swx_table_entry *
595 : : table_pending_modify0_find(struct table *table,
596 : : struct rte_swx_table_entry *entry)
597 : : {
598 : : struct rte_swx_table_entry *e;
599 : :
600 [ # # ]: 0 : TAILQ_FOREACH(e, &table->pending_modify0, node)
601 [ # # ]: 0 : if (!table_entry_keycmp(table, entry, e))
602 : : return e; /* Found. */
603 : :
604 : : return NULL; /* Not found. */
605 : : }
606 : :
607 : : static void
608 : : table_pending_modify0_admit(struct table *table)
609 : : {
610 [ # # ]: 0 : TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
611 : : }
612 : :
613 : : static void
614 : 0 : table_pending_modify0_free(struct table *table)
615 : : {
616 : 0 : for ( ; ; ) {
617 : : struct rte_swx_table_entry *entry;
618 : :
619 : 0 : entry = TAILQ_FIRST(&table->pending_modify0);
620 [ # # ]: 0 : if (!entry)
621 : : break;
622 : :
623 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify0, entry, node);
624 : 0 : table_entry_free(entry);
625 : : }
626 : 0 : }
627 : :
628 : : static struct rte_swx_table_entry *
629 : : table_pending_modify1_find(struct table *table,
630 : : struct rte_swx_table_entry *entry)
631 : : {
632 : : struct rte_swx_table_entry *e;
633 : :
634 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->pending_modify1, node)
635 [ # # # # ]: 0 : if (!table_entry_keycmp(table, entry, e))
636 : : return e; /* Found. */
637 : :
638 : : return NULL; /* Not found. */
639 : : }
640 : :
641 : : static void
642 : : table_pending_modify1_admit(struct table *table)
643 : : {
644 [ # # ]: 0 : TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
645 : : }
646 : :
647 : : static void
648 : 0 : table_pending_modify1_free(struct table *table)
649 : : {
650 : 0 : for ( ; ; ) {
651 : : struct rte_swx_table_entry *entry;
652 : :
653 : 0 : entry = TAILQ_FIRST(&table->pending_modify1);
654 [ # # ]: 0 : if (!entry)
655 : : break;
656 : :
657 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify1, entry, node);
658 : 0 : table_entry_free(entry);
659 : : }
660 : 0 : }
661 : :
662 : : static struct rte_swx_table_entry *
663 : : table_pending_delete_find(struct table *table,
664 : : struct rte_swx_table_entry *entry)
665 : : {
666 : : struct rte_swx_table_entry *e;
667 : :
668 [ # # ]: 0 : TAILQ_FOREACH(e, &table->pending_delete, node)
669 [ # # ]: 0 : if (!table_entry_keycmp(table, entry, e))
670 : : return e; /* Found. */
671 : :
672 : : return NULL; /* Not found. */
673 : : }
674 : :
675 : : static void
676 : : table_pending_delete_admit(struct table *table)
677 : : {
678 [ # # ]: 0 : TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
679 : : }
680 : :
681 : : static void
682 : 0 : table_pending_delete_free(struct table *table)
683 : : {
684 : 0 : for ( ; ; ) {
685 : : struct rte_swx_table_entry *entry;
686 : :
687 : 0 : entry = TAILQ_FIRST(&table->pending_delete);
688 [ # # ]: 0 : if (!entry)
689 : : break;
690 : :
691 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_delete, entry, node);
692 : 0 : table_entry_free(entry);
693 : : }
694 : 0 : }
695 : :
696 : : static void
697 : 0 : table_pending_default_free(struct table *table)
698 : : {
699 [ # # ]: 0 : if (!table->pending_default)
700 : : return;
701 : :
702 : 0 : free(table->pending_default->action_data);
703 : 0 : free(table->pending_default);
704 : 0 : table->pending_default = NULL;
705 : : }
706 : :
707 : : static int
708 : : table_is_update_pending(struct table *table, int consider_pending_default)
709 : : {
710 : : struct rte_swx_table_entry *e;
711 : : uint32_t n = 0;
712 : :
713 : : /* Pending add. */
714 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->pending_add, node)
715 : 0 : n++;
716 : :
717 : : /* Pending modify. */
718 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->pending_modify1, node)
719 : 0 : n++;
720 : :
721 : : /* Pending delete. */
722 [ # # # # ]: 0 : TAILQ_FOREACH(e, &table->pending_delete, node)
723 : 0 : n++;
724 : :
725 : : /* Pending default. */
726 : : if (consider_pending_default && table->pending_default)
727 : : n++;
728 : :
729 : 0 : return n;
730 : : }
731 : :
732 : : static void
733 : 0 : table_free(struct rte_swx_ctl_pipeline *ctl)
734 : : {
735 : : uint32_t i;
736 : :
737 [ # # ]: 0 : if (!ctl->tables)
738 : : return;
739 : :
740 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
741 : 0 : struct table *table = &ctl->tables[i];
742 : :
743 : 0 : free(table->mf);
744 : 0 : free(table->actions);
745 : 0 : free(table->params.key_mask0);
746 : :
747 : 0 : table_entries_free(table);
748 : 0 : table_pending_add_free(table);
749 : 0 : table_pending_modify0_free(table);
750 : 0 : table_pending_modify1_free(table);
751 : 0 : table_pending_delete_free(table);
752 : 0 : table_pending_default_free(table);
753 : : }
754 : :
755 : 0 : free(ctl->tables);
756 : 0 : ctl->tables = NULL;
757 : : }
758 : :
759 : : static void
760 : 0 : selector_group_members_free(struct selector *s, uint32_t group_id)
761 : : {
762 : 0 : struct rte_swx_table_selector_group *group = s->groups[group_id];
763 : :
764 [ # # ]: 0 : if (!group)
765 : : return;
766 : :
767 : 0 : for ( ; ; ) {
768 : : struct rte_swx_table_selector_member *m;
769 : :
770 : 0 : m = TAILQ_FIRST(&group->members);
771 [ # # ]: 0 : if (!m)
772 : : break;
773 : :
774 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
775 : 0 : free(m);
776 : : }
777 : :
778 : 0 : free(group);
779 : 0 : s->groups[group_id] = NULL;
780 : : }
781 : :
782 : : static void
783 : 0 : selector_pending_group_members_free(struct selector *s, uint32_t group_id)
784 : : {
785 : 0 : struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
786 : :
787 [ # # ]: 0 : if (!group)
788 : : return;
789 : :
790 : 0 : for ( ; ; ) {
791 : : struct rte_swx_table_selector_member *m;
792 : :
793 : 0 : m = TAILQ_FIRST(&group->members);
794 [ # # ]: 0 : if (!m)
795 : : break;
796 : :
797 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
798 : 0 : free(m);
799 : : }
800 : :
801 : 0 : free(group);
802 : 0 : s->pending_groups[group_id] = NULL;
803 : : }
804 : :
805 : : static int
806 : 0 : selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
807 : : {
808 : : struct rte_swx_table_selector_group *g, *gp;
809 : : struct rte_swx_table_selector_member *m;
810 : :
811 : 0 : selector_pending_group_members_free(s, group_id);
812 : :
813 : 0 : g = s->groups[group_id];
814 : 0 : gp = s->pending_groups[group_id];
815 : :
816 [ # # ]: 0 : if (!gp) {
817 : 0 : gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
818 [ # # ]: 0 : if (!gp)
819 : 0 : goto error;
820 : :
821 : 0 : TAILQ_INIT(&gp->members);
822 : :
823 : 0 : s->pending_groups[group_id] = gp;
824 : : }
825 : :
826 [ # # ]: 0 : if (!g)
827 : : return 0;
828 : :
829 [ # # ]: 0 : TAILQ_FOREACH(m, &g->members, node) {
830 : : struct rte_swx_table_selector_member *mp;
831 : :
832 : 0 : mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
833 [ # # ]: 0 : if (!mp)
834 : 0 : goto error;
835 : :
836 : 0 : *mp = *m;
837 : :
838 : 0 : TAILQ_INSERT_TAIL(&gp->members, mp, node);
839 : : }
840 : :
841 : : return 0;
842 : :
843 : 0 : error:
844 : 0 : selector_pending_group_members_free(s, group_id);
845 : 0 : return -ENOMEM;
846 : : }
847 : :
848 : : static void
849 : 0 : selector_free(struct rte_swx_ctl_pipeline *ctl)
850 : : {
851 : : uint32_t i;
852 : :
853 [ # # ]: 0 : if (!ctl->selectors)
854 : : return;
855 : :
856 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
857 : 0 : struct selector *s = &ctl->selectors[i];
858 : :
859 : : /* selector_fields. */
860 : 0 : free(s->selector_fields);
861 : :
862 : : /* groups. */
863 [ # # ]: 0 : if (s->groups)
864 [ # # ]: 0 : for (uint32_t j = 0; j < s->info.n_groups_max; j++)
865 : 0 : selector_group_members_free(s, j);
866 : :
867 : 0 : free(s->groups);
868 : :
869 : : /* pending_groups. */
870 [ # # ]: 0 : if (s->pending_groups)
871 [ # # ]: 0 : for (uint32_t j = 0; j < s->info.n_groups_max; j++)
872 : 0 : selector_pending_group_members_free(s, j);
873 : :
874 : 0 : free(s->pending_groups);
875 : :
876 : : /* groups_added. */
877 : 0 : free(s->groups_added);
878 : :
879 : : /* groups_pending_delete. */
880 : 0 : free(s->groups_pending_delete);
881 : :
882 : : /* params. */
883 : 0 : free(s->params.selector_mask);
884 : : }
885 : :
886 : 0 : free(ctl->selectors);
887 : 0 : ctl->selectors = NULL;
888 : : }
889 : :
890 : : static struct selector *
891 : 0 : selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
892 : : {
893 : : uint32_t i;
894 : :
895 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
896 : 0 : struct selector *s = &ctl->selectors[i];
897 : :
898 [ # # ]: 0 : if (!strcmp(selector_name, s->info.name))
899 : 0 : return s;
900 : : }
901 : :
902 : : return NULL;
903 : : }
904 : :
905 : : static int
906 : 0 : selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
907 : : {
908 : 0 : struct selector *s = &ctl->selectors[selector_id];
909 : : struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
910 : : uint8_t *selector_mask = NULL;
911 : : uint32_t selector_size = 0, selector_offset = 0, i;
912 : :
913 : : /* Find first (smallest offset) and last (biggest offset) match fields. */
914 : 0 : first = &s->selector_fields[0];
915 : : last = &s->selector_fields[0];
916 : :
917 [ # # ]: 0 : for (i = 1; i < s->info.n_selector_fields; i++) {
918 : 0 : struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
919 : :
920 [ # # ]: 0 : if (f->offset < first->offset)
921 : : first = f;
922 : :
923 [ # # ]: 0 : if (f->offset > last->offset)
924 : : last = f;
925 : : }
926 : :
927 : : /* selector_offset. */
928 : 0 : selector_offset = first->offset / 8;
929 : :
930 : : /* selector_size. */
931 : 0 : selector_size = (last->offset + last->n_bits - first->offset) / 8;
932 : :
933 : : /* selector_mask. */
934 : 0 : selector_mask = calloc(1, selector_size);
935 [ # # ]: 0 : if (!selector_mask)
936 : : return -ENOMEM;
937 : :
938 [ # # ]: 0 : for (i = 0; i < s->info.n_selector_fields; i++) {
939 : 0 : struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
940 : : uint32_t start;
941 : : size_t size;
942 : :
943 : 0 : start = (f->offset - first->offset) / 8;
944 : 0 : size = f->n_bits / 8;
945 : :
946 : 0 : memset(&selector_mask[start], 0xFF, size);
947 : : }
948 : :
949 : : /* Fill in. */
950 : 0 : s->params.group_id_offset = s->group_id_field.offset / 8;
951 : 0 : s->params.selector_size = selector_size;
952 : 0 : s->params.selector_offset = selector_offset;
953 : 0 : s->params.selector_mask = selector_mask;
954 : 0 : s->params.member_id_offset = s->member_id_field.offset / 8;
955 : 0 : s->params.n_groups_max = s->info.n_groups_max;
956 : 0 : s->params.n_members_per_group_max = s->info.n_members_per_group_max;
957 : :
958 : 0 : return 0;
959 : : }
960 : :
961 : : static void
962 : 0 : learner_pending_default_free(struct learner *l)
963 : : {
964 [ # # ]: 0 : if (!l->pending_default)
965 : : return;
966 : :
967 : 0 : free(l->pending_default->action_data);
968 : 0 : free(l->pending_default);
969 : 0 : l->pending_default = NULL;
970 : : }
971 : :
972 : :
973 : : static void
974 : 0 : learner_free(struct rte_swx_ctl_pipeline *ctl)
975 : : {
976 : : uint32_t i;
977 : :
978 [ # # ]: 0 : if (!ctl->learners)
979 : : return;
980 : :
981 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
982 : 0 : struct learner *l = &ctl->learners[i];
983 : :
984 : 0 : free(l->mf);
985 : 0 : free(l->actions);
986 : :
987 : 0 : learner_pending_default_free(l);
988 : : }
989 : :
990 : 0 : free(ctl->learners);
991 : 0 : ctl->learners = NULL;
992 : : }
993 : :
994 : : static struct learner *
995 : 0 : learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
996 : : {
997 : : uint32_t i;
998 : :
999 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1000 : 0 : struct learner *l = &ctl->learners[i];
1001 : :
1002 [ # # ]: 0 : if (!strcmp(learner_name, l->info.name))
1003 : 0 : return l;
1004 : : }
1005 : :
1006 : : return NULL;
1007 : : }
1008 : :
1009 : : static uint32_t
1010 : : learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1011 : : {
1012 : : uint32_t action_data_size = 0, i;
1013 : :
1014 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++) {
1015 : 0 : uint32_t action_id = l->actions[i].action_id;
1016 : 0 : struct action *a = &ctl->actions[action_id];
1017 : :
1018 : 0 : if (a->data_size > action_data_size)
1019 : : action_data_size = a->data_size;
1020 : : }
1021 : :
1022 : : return action_data_size;
1023 : : }
1024 : :
1025 : : static void
1026 : 0 : table_state_free(struct rte_swx_ctl_pipeline *ctl)
1027 : : {
1028 : : uint32_t table_base_index, selector_base_index, learner_base_index, i;
1029 : :
1030 [ # # ]: 0 : if (!ctl->ts_next)
1031 : : return;
1032 : :
1033 : : /* For each table, free its table state. */
1034 : : table_base_index = 0;
1035 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1036 : 0 : struct table *table = &ctl->tables[i];
1037 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
1038 : :
1039 : : /* Default action data. */
1040 : 0 : free(ts->default_action_data);
1041 : :
1042 : : /* Table object. */
1043 [ # # # # : 0 : if (!table->is_stub && table->ops.free && ts->obj)
# # ]
1044 : 0 : table->ops.free(ts->obj);
1045 : : }
1046 : :
1047 : : /* For each selector table, free its table state. */
1048 : : selector_base_index = ctl->info.n_tables;
1049 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1050 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1051 : :
1052 : : /* Table object. */
1053 : 0 : rte_swx_table_selector_free(ts->obj);
1054 : : }
1055 : :
1056 : : /* For each learner table, free its table state. */
1057 : 0 : learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1058 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1059 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1060 : :
1061 : : /* Default action data. */
1062 : 0 : free(ts->default_action_data);
1063 : : }
1064 : :
1065 : 0 : free(ctl->ts_next);
1066 : 0 : ctl->ts_next = NULL;
1067 : : }
1068 : :
1069 : : static int
1070 : 0 : table_state_create(struct rte_swx_ctl_pipeline *ctl)
1071 : : {
1072 : : uint32_t table_base_index, selector_base_index, learner_base_index, i;
1073 : : int status = 0;
1074 : :
1075 : 0 : ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1076 : : sizeof(struct rte_swx_table_state));
1077 [ # # ]: 0 : if (!ctl->ts_next) {
1078 : : status = -ENOMEM;
1079 : 0 : goto error;
1080 : : }
1081 : :
1082 : : /* Tables. */
1083 : : table_base_index = 0;
1084 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1085 : 0 : struct table *table = &ctl->tables[i];
1086 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1087 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1088 : :
1089 : : /* Table object. */
1090 [ # # # # ]: 0 : if (!table->is_stub && table->ops.add) {
1091 : 0 : ts_next->obj = table->ops.create(&table->params,
1092 : : &table->entries,
1093 : 0 : table->info.args,
1094 : : ctl->numa_node);
1095 [ # # ]: 0 : if (!ts_next->obj) {
1096 : : status = -ENODEV;
1097 : 0 : goto error;
1098 : : }
1099 : : }
1100 : :
1101 [ # # # # ]: 0 : if (!table->is_stub && !table->ops.add)
1102 : 0 : ts_next->obj = ts->obj;
1103 : :
1104 : : /* Default action data: duplicate from current table state. */
1105 : 0 : ts_next->default_action_data =
1106 : 0 : malloc(table->params.action_data_size);
1107 [ # # ]: 0 : if (!ts_next->default_action_data) {
1108 : : status = -ENOMEM;
1109 : 0 : goto error;
1110 : : }
1111 : :
1112 : : memcpy(ts_next->default_action_data,
1113 : 0 : ts->default_action_data,
1114 : : table->params.action_data_size);
1115 : :
1116 : 0 : ts_next->default_action_id = ts->default_action_id;
1117 : : }
1118 : :
1119 : : /* Selector tables. */
1120 : : selector_base_index = ctl->info.n_tables;
1121 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1122 : 0 : struct selector *s = &ctl->selectors[i];
1123 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1124 : :
1125 : : /* Table object. */
1126 : 0 : ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1127 [ # # ]: 0 : if (!ts_next->obj) {
1128 : : status = -ENODEV;
1129 : 0 : goto error;
1130 : : }
1131 : : }
1132 : :
1133 : : /* Learner tables. */
1134 : 0 : learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1135 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1136 : 0 : struct learner *l = &ctl->learners[i];
1137 : 0 : struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1138 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1139 : :
1140 : : /* Table object: duplicate from the current table state. */
1141 : 0 : ts_next->obj = ts->obj;
1142 : :
1143 : : /* Default action data: duplicate from the current table state. */
1144 : 0 : ts_next->default_action_data = malloc(l->action_data_size);
1145 [ # # ]: 0 : if (!ts_next->default_action_data) {
1146 : : status = -ENOMEM;
1147 : 0 : goto error;
1148 : : }
1149 : :
1150 : : memcpy(ts_next->default_action_data,
1151 : 0 : ts->default_action_data,
1152 : : l->action_data_size);
1153 : :
1154 : 0 : ts_next->default_action_id = ts->default_action_id;
1155 : : }
1156 : :
1157 : : return 0;
1158 : :
1159 : 0 : error:
1160 : 0 : table_state_free(ctl);
1161 : 0 : return status;
1162 : : }
1163 : :
1164 : : /* Global list of pipeline instances. */
1165 : : TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
1166 : :
1167 : : static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
1168 : : .name = "RTE_SWX_CTL_PIPELINE",
1169 : : };
1170 : :
1171 [ - + ]: 258 : EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
1172 : :
1173 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_find, 22.11)
1174 : : struct rte_swx_ctl_pipeline *
1175 : 0 : rte_swx_ctl_pipeline_find(const char *name)
1176 : : {
1177 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1178 : : struct rte_tailq_entry *te = NULL;
1179 : :
1180 [ # # # # : 0 : if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
# # ]
1181 : : return NULL;
1182 : :
1183 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1184 : :
1185 : 0 : rte_mcfg_tailq_read_lock();
1186 : :
1187 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1188 : 0 : struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
1189 : :
1190 [ # # ]: 0 : if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
1191 : 0 : rte_mcfg_tailq_read_unlock();
1192 : 0 : return ctl;
1193 : : }
1194 : : }
1195 : :
1196 : 0 : rte_mcfg_tailq_read_unlock();
1197 : 0 : return NULL;
1198 : : }
1199 : :
1200 : : static int
1201 : 0 : ctl_register(struct rte_swx_ctl_pipeline *ctl)
1202 : : {
1203 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1204 : : struct rte_tailq_entry *te = NULL;
1205 : :
1206 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1207 : :
1208 : 0 : rte_mcfg_tailq_write_lock();
1209 : :
1210 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1211 : 0 : struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
1212 : :
1213 [ # # ]: 0 : if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
1214 : 0 : rte_mcfg_tailq_write_unlock();
1215 : 0 : return -EEXIST;
1216 : : }
1217 : : }
1218 : :
1219 : 0 : te = calloc(1, sizeof(struct rte_tailq_entry));
1220 [ # # ]: 0 : if (!te) {
1221 : 0 : rte_mcfg_tailq_write_unlock();
1222 : 0 : return -ENOMEM;
1223 : : }
1224 : :
1225 : 0 : te->data = (void *)ctl;
1226 : 0 : TAILQ_INSERT_TAIL(ctl_list, te, next);
1227 : 0 : rte_mcfg_tailq_write_unlock();
1228 : 0 : return 0;
1229 : : }
1230 : :
1231 : : static void
1232 : 0 : ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
1233 : : {
1234 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1235 : : struct rte_tailq_entry *te = NULL;
1236 : :
1237 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1238 : :
1239 : 0 : rte_mcfg_tailq_write_lock();
1240 : :
1241 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1242 [ # # ]: 0 : if (te->data == (void *)ctl) {
1243 [ # # ]: 0 : TAILQ_REMOVE(ctl_list, te, next);
1244 : 0 : rte_mcfg_tailq_write_unlock();
1245 : 0 : free(te);
1246 : 0 : return;
1247 : : }
1248 : : }
1249 : :
1250 : 0 : rte_mcfg_tailq_write_unlock();
1251 : : }
1252 : :
1253 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_free, 20.11)
1254 : : void
1255 : 0 : rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1256 : : {
1257 [ # # ]: 0 : if (!ctl)
1258 : : return;
1259 : :
1260 [ # # ]: 0 : if (ctl->info.name[0])
1261 : 0 : ctl_unregister(ctl);
1262 : :
1263 : 0 : action_free(ctl);
1264 : :
1265 : 0 : table_state_free(ctl);
1266 : :
1267 : 0 : learner_free(ctl);
1268 : :
1269 : 0 : selector_free(ctl);
1270 : :
1271 : 0 : table_free(ctl);
1272 : :
1273 : 0 : free(ctl);
1274 : : }
1275 : :
1276 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_create, 20.11)
1277 : : struct rte_swx_ctl_pipeline *
1278 : 0 : rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1279 : : {
1280 : : struct rte_swx_ctl_pipeline *ctl = NULL;
1281 : : uint32_t i;
1282 : : int status;
1283 : :
1284 [ # # ]: 0 : if (!p)
1285 : 0 : goto error;
1286 : :
1287 : 0 : ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1288 [ # # ]: 0 : if (!ctl)
1289 : 0 : goto error;
1290 : :
1291 : : /* info. */
1292 : 0 : status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1293 [ # # ]: 0 : if (status)
1294 : 0 : goto error;
1295 : :
1296 : : /* numa_node. */
1297 : 0 : status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1298 [ # # ]: 0 : if (status)
1299 : 0 : goto error;
1300 : :
1301 : : /* p. */
1302 : 0 : ctl->p = p;
1303 : :
1304 : : /* actions. */
1305 : 0 : ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1306 [ # # ]: 0 : if (!ctl->actions)
1307 : 0 : goto error;
1308 : :
1309 [ # # ]: 0 : for (i = 0; i < ctl->info.n_actions; i++) {
1310 : 0 : struct action *a = &ctl->actions[i];
1311 : : uint32_t j;
1312 : :
1313 : : /* info. */
1314 : 0 : status = rte_swx_ctl_action_info_get(p, i, &a->info);
1315 [ # # ]: 0 : if (status)
1316 : 0 : goto error;
1317 : :
1318 : : /* args. */
1319 : 0 : a->args = calloc(a->info.n_args,
1320 : : sizeof(struct rte_swx_ctl_action_arg_info));
1321 [ # # ]: 0 : if (!a->args)
1322 : 0 : goto error;
1323 : :
1324 [ # # ]: 0 : for (j = 0; j < a->info.n_args; j++) {
1325 : 0 : status = rte_swx_ctl_action_arg_info_get(p,
1326 : : i,
1327 : : j,
1328 : 0 : &a->args[j]);
1329 [ # # ]: 0 : if (status)
1330 : 0 : goto error;
1331 : : }
1332 : :
1333 : : /* data_size. */
1334 [ # # ]: 0 : for (j = 0; j < a->info.n_args; j++) {
1335 : 0 : struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1336 : :
1337 : 0 : a->data_size += info->n_bits;
1338 : : }
1339 : :
1340 : 0 : a->data_size = (a->data_size + 7) / 8;
1341 : : }
1342 : :
1343 : : /* tables. */
1344 : 0 : ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1345 [ # # ]: 0 : if (!ctl->tables)
1346 : 0 : goto error;
1347 : :
1348 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1349 : 0 : struct table *t = &ctl->tables[i];
1350 : :
1351 : 0 : TAILQ_INIT(&t->entries);
1352 : 0 : TAILQ_INIT(&t->pending_add);
1353 : 0 : TAILQ_INIT(&t->pending_modify0);
1354 : 0 : TAILQ_INIT(&t->pending_modify1);
1355 : 0 : TAILQ_INIT(&t->pending_delete);
1356 : : }
1357 : :
1358 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1359 : 0 : struct table *t = &ctl->tables[i];
1360 : : uint32_t j;
1361 : :
1362 : : /* info. */
1363 : 0 : status = rte_swx_ctl_table_info_get(p, i, &t->info);
1364 [ # # ]: 0 : if (status)
1365 : 0 : goto error;
1366 : :
1367 : : /* mf. */
1368 : 0 : t->mf = calloc(t->info.n_match_fields,
1369 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1370 [ # # ]: 0 : if (!t->mf)
1371 : 0 : goto error;
1372 : :
1373 [ # # ]: 0 : for (j = 0; j < t->info.n_match_fields; j++) {
1374 : 0 : status = rte_swx_ctl_table_match_field_info_get(p,
1375 : : i,
1376 : : j,
1377 : 0 : &t->mf[j]);
1378 [ # # ]: 0 : if (status)
1379 : 0 : goto error;
1380 : : }
1381 : :
1382 : : /* actions. */
1383 : 0 : t->actions = calloc(t->info.n_actions,
1384 : : sizeof(struct rte_swx_ctl_table_action_info));
1385 [ # # ]: 0 : if (!t->actions)
1386 : 0 : goto error;
1387 : :
1388 [ # # ]: 0 : for (j = 0; j < t->info.n_actions; j++) {
1389 : 0 : status = rte_swx_ctl_table_action_info_get(p,
1390 : : i,
1391 : : j,
1392 : 0 : &t->actions[j]);
1393 [ # # ]: 0 : if (status ||
1394 [ # # ]: 0 : t->actions[j].action_id >= ctl->info.n_actions)
1395 : 0 : goto error;
1396 : : }
1397 : :
1398 : : /* ops, is_stub. */
1399 : 0 : status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1400 [ # # ]: 0 : if (status)
1401 : 0 : goto error;
1402 : :
1403 [ # # # # : 0 : if ((t->is_stub && t->info.n_match_fields) ||
# # ]
1404 [ # # ]: 0 : (!t->is_stub && !t->info.n_match_fields))
1405 : 0 : goto error;
1406 : :
1407 : : /* params. */
1408 : 0 : status = table_params_get(ctl, i);
1409 [ # # ]: 0 : if (status)
1410 : 0 : goto error;
1411 : : }
1412 : :
1413 : : /* selector tables. */
1414 : 0 : ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1415 [ # # ]: 0 : if (!ctl->selectors)
1416 : 0 : goto error;
1417 : :
1418 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1419 : 0 : struct selector *s = &ctl->selectors[i];
1420 : : uint32_t j;
1421 : :
1422 : : /* info. */
1423 : 0 : status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1424 [ # # ]: 0 : if (status)
1425 : 0 : goto error;
1426 : :
1427 : : /* group_id field. */
1428 : 0 : status = rte_swx_ctl_selector_group_id_field_info_get(p,
1429 : : i,
1430 : : &s->group_id_field);
1431 [ # # ]: 0 : if (status)
1432 : 0 : goto error;
1433 : :
1434 : : /* selector fields. */
1435 : 0 : s->selector_fields = calloc(s->info.n_selector_fields,
1436 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1437 [ # # ]: 0 : if (!s->selector_fields)
1438 : 0 : goto error;
1439 : :
1440 [ # # ]: 0 : for (j = 0; j < s->info.n_selector_fields; j++) {
1441 : 0 : status = rte_swx_ctl_selector_field_info_get(p,
1442 : : i,
1443 : : j,
1444 : 0 : &s->selector_fields[j]);
1445 [ # # ]: 0 : if (status)
1446 : 0 : goto error;
1447 : : }
1448 : :
1449 : : /* member_id field. */
1450 : 0 : status = rte_swx_ctl_selector_member_id_field_info_get(p,
1451 : : i,
1452 : : &s->member_id_field);
1453 [ # # ]: 0 : if (status)
1454 : 0 : goto error;
1455 : :
1456 : : /* groups. */
1457 : 0 : s->groups = calloc(s->info.n_groups_max,
1458 : : sizeof(struct rte_swx_table_selector_group *));
1459 [ # # ]: 0 : if (!s->groups)
1460 : 0 : goto error;
1461 : :
1462 : : /* pending_groups. */
1463 : 0 : s->pending_groups = calloc(s->info.n_groups_max,
1464 : : sizeof(struct rte_swx_table_selector_group *));
1465 [ # # ]: 0 : if (!s->pending_groups)
1466 : 0 : goto error;
1467 : :
1468 : : /* groups_added. */
1469 : 0 : s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1470 [ # # ]: 0 : if (!s->groups_added)
1471 : 0 : goto error;
1472 : :
1473 : : /* groups_pending_delete. */
1474 : 0 : s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1475 [ # # ]: 0 : if (!s->groups_pending_delete)
1476 : 0 : goto error;
1477 : :
1478 : : /* params. */
1479 : 0 : status = selector_params_get(ctl, i);
1480 [ # # ]: 0 : if (status)
1481 : 0 : goto error;
1482 : : }
1483 : :
1484 : : /* learner tables. */
1485 : 0 : ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1486 [ # # ]: 0 : if (!ctl->learners)
1487 : 0 : goto error;
1488 : :
1489 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1490 : 0 : struct learner *l = &ctl->learners[i];
1491 : : uint32_t j;
1492 : :
1493 : : /* info. */
1494 : 0 : status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1495 [ # # ]: 0 : if (status)
1496 : 0 : goto error;
1497 : :
1498 : : /* mf. */
1499 : 0 : l->mf = calloc(l->info.n_match_fields,
1500 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1501 [ # # ]: 0 : if (!l->mf)
1502 : 0 : goto error;
1503 : :
1504 [ # # ]: 0 : for (j = 0; j < l->info.n_match_fields; j++) {
1505 : 0 : status = rte_swx_ctl_learner_match_field_info_get(p,
1506 : : i,
1507 : : j,
1508 : 0 : &l->mf[j]);
1509 [ # # ]: 0 : if (status)
1510 : 0 : goto error;
1511 : : }
1512 : :
1513 : : /* actions. */
1514 : 0 : l->actions = calloc(l->info.n_actions,
1515 : : sizeof(struct rte_swx_ctl_table_action_info));
1516 [ # # ]: 0 : if (!l->actions)
1517 : 0 : goto error;
1518 : :
1519 [ # # ]: 0 : for (j = 0; j < l->info.n_actions; j++) {
1520 : 0 : status = rte_swx_ctl_learner_action_info_get(p,
1521 : : i,
1522 : : j,
1523 : 0 : &l->actions[j]);
1524 [ # # # # ]: 0 : if (status || l->actions[j].action_id >= ctl->info.n_actions)
1525 : 0 : goto error;
1526 : : }
1527 : :
1528 : : /* action_data_size. */
1529 : 0 : l->action_data_size = learner_action_data_size_get(ctl, l);
1530 : : }
1531 : :
1532 : : /* ts. */
1533 : 0 : status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1534 [ # # ]: 0 : if (status)
1535 : 0 : goto error;
1536 : :
1537 : : /* ts_next. */
1538 : 0 : status = table_state_create(ctl);
1539 [ # # ]: 0 : if (status)
1540 : 0 : goto error;
1541 : :
1542 [ # # ]: 0 : if (ctl->info.name[0]) {
1543 : 0 : status = ctl_register(ctl);
1544 [ # # ]: 0 : if (status)
1545 : 0 : goto error;
1546 : : }
1547 : :
1548 : : return ctl;
1549 : :
1550 : 0 : error:
1551 : 0 : rte_swx_ctl_pipeline_free(ctl);
1552 : 0 : return NULL;
1553 : : }
1554 : :
1555 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_add, 20.11)
1556 : : int
1557 : 0 : rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1558 : : const char *table_name,
1559 : : struct rte_swx_table_entry *entry)
1560 : : {
1561 : : struct table *table;
1562 : : struct rte_swx_table_entry *new_entry, *existing_entry;
1563 : : uint32_t table_id;
1564 : :
1565 [ # # ]: 0 : CHECK(ctl, EINVAL);
1566 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1567 : :
1568 : 0 : table = table_find(ctl, table_name);
1569 [ # # ]: 0 : CHECK(table, EINVAL);
1570 : 0 : table_id = table - ctl->tables;
1571 : :
1572 [ # # ]: 0 : CHECK(entry, EINVAL);
1573 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1574 : :
1575 : 0 : new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1576 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
1577 : :
1578 : : /* The new entry is found in the table->entries list:
1579 : : * - Add the new entry to the table->pending_modify1 list;
1580 : : * - Move the existing entry from the table->entries list to the
1581 : : * table->pending_modify0 list.
1582 : : */
1583 : : existing_entry = table_entries_find(table, entry);
1584 [ # # ]: 0 : if (existing_entry) {
1585 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify1,
1586 : : new_entry,
1587 : : node);
1588 : :
1589 [ # # ]: 0 : TAILQ_REMOVE(&table->entries,
1590 : : existing_entry,
1591 : : node);
1592 : :
1593 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify0,
1594 : : existing_entry,
1595 : : node);
1596 : :
1597 : 0 : return 0;
1598 : : }
1599 : :
1600 : : /* The new entry is found in the table->pending_add list:
1601 : : * - Replace the entry in the table->pending_add list with the new entry
1602 : : * (and free the replaced entry).
1603 : : */
1604 : : existing_entry = table_pending_add_find(table, entry);
1605 [ # # ]: 0 : if (existing_entry) {
1606 [ # # ]: 0 : TAILQ_INSERT_AFTER(&table->pending_add,
1607 : : existing_entry,
1608 : : new_entry,
1609 : : node);
1610 : :
1611 : 0 : TAILQ_REMOVE(&table->pending_add,
1612 : : existing_entry,
1613 : : node);
1614 : :
1615 : 0 : table_entry_free(existing_entry);
1616 : :
1617 : 0 : return 0;
1618 : : }
1619 : :
1620 : : /* The new entry is found in the table->pending_modify1 list:
1621 : : * - Replace the entry in the table->pending_modify1 list with the new
1622 : : * entry (and free the replaced entry).
1623 : : */
1624 : : existing_entry = table_pending_modify1_find(table, entry);
1625 [ # # ]: 0 : if (existing_entry) {
1626 [ # # ]: 0 : TAILQ_INSERT_AFTER(&table->pending_modify1,
1627 : : existing_entry,
1628 : : new_entry,
1629 : : node);
1630 : :
1631 : 0 : TAILQ_REMOVE(&table->pending_modify1,
1632 : : existing_entry,
1633 : : node);
1634 : :
1635 : 0 : table_entry_free(existing_entry);
1636 : :
1637 : 0 : return 0;
1638 : : }
1639 : :
1640 : : /* The new entry is found in the table->pending_delete list:
1641 : : * - Add the new entry to the table->pending_modify1 list;
1642 : : * - Move the existing entry from the table->pending_delete list to the
1643 : : * table->pending_modify0 list.
1644 : : */
1645 : : existing_entry = table_pending_delete_find(table, entry);
1646 [ # # ]: 0 : if (existing_entry) {
1647 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify1,
1648 : : new_entry,
1649 : : node);
1650 : :
1651 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_delete,
1652 : : existing_entry,
1653 : : node);
1654 : :
1655 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify0,
1656 : : existing_entry,
1657 : : node);
1658 : :
1659 : 0 : return 0;
1660 : : }
1661 : :
1662 : : /* The new entry is not found in any of the above lists:
1663 : : * - Add the new entry to the table->pending_add list.
1664 : : */
1665 : 0 : TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1666 : :
1667 : 0 : return 0;
1668 : : }
1669 : :
1670 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_delete, 20.11)
1671 : : int
1672 : 0 : rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1673 : : const char *table_name,
1674 : : struct rte_swx_table_entry *entry)
1675 : : {
1676 : : struct table *table;
1677 : : struct rte_swx_table_entry *existing_entry;
1678 : : uint32_t table_id;
1679 : :
1680 [ # # ]: 0 : CHECK(ctl, EINVAL);
1681 : :
1682 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1683 : 0 : table = table_find(ctl, table_name);
1684 [ # # ]: 0 : CHECK(table, EINVAL);
1685 : 0 : table_id = table - ctl->tables;
1686 : :
1687 [ # # ]: 0 : CHECK(entry, EINVAL);
1688 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1689 : :
1690 : : /* The entry is found in the table->entries list:
1691 : : * - Move the existing entry from the table->entries list to the
1692 : : * table->pending_delete list.
1693 : : */
1694 : : existing_entry = table_entries_find(table, entry);
1695 [ # # ]: 0 : if (existing_entry) {
1696 [ # # ]: 0 : TAILQ_REMOVE(&table->entries,
1697 : : existing_entry,
1698 : : node);
1699 : :
1700 : 0 : TAILQ_INSERT_TAIL(&table->pending_delete,
1701 : : existing_entry,
1702 : : node);
1703 : :
1704 : 0 : return 0;
1705 : : }
1706 : :
1707 : : /* The entry is found in the table->pending_add list:
1708 : : * - Remove the entry from the table->pending_add list and free it.
1709 : : */
1710 : : existing_entry = table_pending_add_find(table, entry);
1711 [ # # ]: 0 : if (existing_entry) {
1712 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_add,
1713 : : existing_entry,
1714 : : node);
1715 : :
1716 : 0 : table_entry_free(existing_entry);
1717 : : }
1718 : :
1719 : : /* The entry is found in the table->pending_modify1 list:
1720 : : * - Free the entry in the table->pending_modify1 list;
1721 : : * - Move the existing entry from the table->pending_modify0 list to the
1722 : : * table->pending_delete list.
1723 : : */
1724 : : existing_entry = table_pending_modify1_find(table, entry);
1725 [ # # ]: 0 : if (existing_entry) {
1726 : : struct rte_swx_table_entry *real_existing_entry;
1727 : :
1728 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify1,
1729 : : existing_entry,
1730 : : node);
1731 : :
1732 : 0 : table_entry_free(existing_entry);
1733 : :
1734 : : real_existing_entry = table_pending_modify0_find(table, entry);
1735 [ # # ]: 0 : CHECK(real_existing_entry, EINVAL); /* Coverity. */
1736 : :
1737 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify0,
1738 : : real_existing_entry,
1739 : : node);
1740 : :
1741 : 0 : TAILQ_INSERT_TAIL(&table->pending_delete,
1742 : : real_existing_entry,
1743 : : node);
1744 : :
1745 : 0 : return 0;
1746 : : }
1747 : :
1748 : : /* The entry is found in the table->pending_delete list:
1749 : : * - Do nothing: the existing entry is already in the
1750 : : * table->pending_delete list, i.e. already marked for delete, so
1751 : : * simply keep it there as it is.
1752 : : */
1753 : :
1754 : : /* The entry is not found in any of the above lists:
1755 : : * - Do nothing: no existing entry to delete.
1756 : : */
1757 : :
1758 : : return 0;
1759 : : }
1760 : :
1761 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_default_entry_add, 20.11)
1762 : : int
1763 : 0 : rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1764 : : const char *table_name,
1765 : : struct rte_swx_table_entry *entry)
1766 : : {
1767 : : struct table *table;
1768 : : struct rte_swx_table_entry *new_entry;
1769 : : uint32_t table_id;
1770 : :
1771 [ # # ]: 0 : CHECK(ctl, EINVAL);
1772 : :
1773 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1774 : 0 : table = table_find(ctl, table_name);
1775 [ # # ]: 0 : CHECK(table, EINVAL);
1776 : 0 : table_id = table - ctl->tables;
1777 [ # # ]: 0 : CHECK(!table->info.default_action_is_const, EINVAL);
1778 : :
1779 [ # # ]: 0 : CHECK(entry, EINVAL);
1780 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1781 : :
1782 : 0 : new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1783 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
1784 : :
1785 : 0 : table_pending_default_free(table);
1786 : :
1787 : 0 : table->pending_default = new_entry;
1788 : 0 : return 0;
1789 : : }
1790 : :
1791 : :
1792 : : static void
1793 : 0 : table_entry_list_free(struct rte_swx_table_entry_list *list)
1794 : : {
1795 : 0 : for ( ; ; ) {
1796 : : struct rte_swx_table_entry *entry;
1797 : :
1798 : 0 : entry = TAILQ_FIRST(list);
1799 [ # # ]: 0 : if (!entry)
1800 : : break;
1801 : :
1802 [ # # ]: 0 : TAILQ_REMOVE(list, entry, node);
1803 : 0 : table_entry_free(entry);
1804 : : }
1805 : 0 : }
1806 : :
1807 : : static int
1808 : 0 : table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1809 : : uint32_t table_id,
1810 : : struct rte_swx_table_entry_list *dst,
1811 : : struct rte_swx_table_entry_list *src)
1812 : : {
1813 : : struct rte_swx_table_entry *src_entry;
1814 : :
1815 [ # # ]: 0 : TAILQ_FOREACH(src_entry, src, node) {
1816 : : struct rte_swx_table_entry *dst_entry;
1817 : :
1818 : 0 : dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1819 [ # # ]: 0 : if (!dst_entry)
1820 : 0 : goto error;
1821 : :
1822 : 0 : TAILQ_INSERT_TAIL(dst, dst_entry, node);
1823 : : }
1824 : :
1825 : : return 0;
1826 : :
1827 : : error:
1828 : 0 : table_entry_list_free(dst);
1829 : 0 : return -ENOMEM;
1830 : : }
1831 : :
1832 : : /* This commit stage contains all the operations that can fail; in case ANY of
1833 : : * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1834 : : */
1835 : : static int
1836 : 0 : table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1837 : : uint32_t table_id,
1838 : : uint32_t after_swap)
1839 : : {
1840 : 0 : struct table *table = &ctl->tables[table_id];
1841 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_id];
1842 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1843 : :
1844 [ # # # # ]: 0 : if (table->is_stub || !table_is_update_pending(table, 0))
1845 : : return 0;
1846 : :
1847 : : /*
1848 : : * Current table supports incremental update.
1849 : : */
1850 [ # # ]: 0 : if (table->ops.add) {
1851 : : /* Reset counters. */
1852 : 0 : table->n_add = 0;
1853 : 0 : table->n_modify = 0;
1854 : 0 : table->n_delete = 0;
1855 : :
1856 : : /* Add pending rules. */
1857 : : struct rte_swx_table_entry *entry;
1858 : :
1859 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_add, node) {
1860 : : int status;
1861 : :
1862 : 0 : status = table->ops.add(ts_next->obj, entry);
1863 [ # # ]: 0 : if (status)
1864 : 0 : return status;
1865 : :
1866 : 0 : table->n_add++;
1867 : : }
1868 : :
1869 : : /* Modify pending rules. */
1870 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1871 : : int status;
1872 : :
1873 : 0 : status = table->ops.add(ts_next->obj, entry);
1874 [ # # ]: 0 : if (status)
1875 : 0 : return status;
1876 : :
1877 : 0 : table->n_modify++;
1878 : : }
1879 : :
1880 : : /* Delete pending rules. */
1881 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
1882 : : int status;
1883 : :
1884 : 0 : status = table->ops.del(ts_next->obj, entry);
1885 [ # # ]: 0 : if (status)
1886 : 0 : return status;
1887 : :
1888 : 0 : table->n_delete++;
1889 : : }
1890 : :
1891 : : return 0;
1892 : : }
1893 : :
1894 : : /*
1895 : : * Current table does NOT support incremental update.
1896 : : */
1897 [ # # ]: 0 : if (!after_swap) {
1898 : : struct rte_swx_table_entry_list list;
1899 : : int status;
1900 : :
1901 : : /* Create updated list of entries included. */
1902 : 0 : TAILQ_INIT(&list);
1903 : :
1904 : 0 : status = table_entry_list_duplicate(ctl,
1905 : : table_id,
1906 : : &list,
1907 : : &table->entries);
1908 [ # # ]: 0 : if (status)
1909 : 0 : goto error;
1910 : :
1911 : 0 : status = table_entry_list_duplicate(ctl,
1912 : : table_id,
1913 : : &list,
1914 : : &table->pending_add);
1915 [ # # ]: 0 : if (status)
1916 : 0 : goto error;
1917 : :
1918 : 0 : status = table_entry_list_duplicate(ctl,
1919 : : table_id,
1920 : : &list,
1921 : : &table->pending_modify1);
1922 [ # # ]: 0 : if (status)
1923 : 0 : goto error;
1924 : :
1925 : : /* Create new table object with the updates included. */
1926 : 0 : ts_next->obj = table->ops.create(&table->params,
1927 : : &list,
1928 : 0 : table->info.args,
1929 : : ctl->numa_node);
1930 [ # # ]: 0 : if (!ts_next->obj) {
1931 : : status = -ENODEV;
1932 : 0 : goto error;
1933 : : }
1934 : :
1935 : 0 : table_entry_list_free(&list);
1936 : :
1937 : 0 : return 0;
1938 : :
1939 : 0 : error:
1940 : 0 : table_entry_list_free(&list);
1941 : 0 : return status;
1942 : : }
1943 : :
1944 : : /* Free the old table object. */
1945 [ # # # # ]: 0 : if (ts_next->obj && table->ops.free)
1946 : 0 : table->ops.free(ts_next->obj);
1947 : :
1948 : : /* Copy over the new table object. */
1949 : 0 : ts_next->obj = ts->obj;
1950 : :
1951 : 0 : return 0;
1952 : : }
1953 : :
1954 : : /* This commit stage contains all the operations that cannot fail. They are
1955 : : * executed only if the previous stage was successful for ALL the tables. Hence,
1956 : : * none of these operations has to be rolled back for ANY table.
1957 : : */
1958 : : static void
1959 : 0 : table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1960 : : {
1961 : 0 : struct table *table = &ctl->tables[table_id];
1962 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1963 : : struct action *a;
1964 : : uint8_t *action_data;
1965 : : uint64_t action_id;
1966 : :
1967 : : /* Copy the pending default entry. */
1968 [ # # ]: 0 : if (!table->pending_default)
1969 : : return;
1970 : :
1971 : 0 : action_id = table->pending_default->action_id;
1972 : 0 : action_data = table->pending_default->action_data;
1973 : 0 : a = &ctl->actions[action_id];
1974 : :
1975 [ # # ]: 0 : if (a->data_size)
1976 : 0 : memcpy(ts_next->default_action_data, action_data, a->data_size);
1977 : :
1978 : 0 : ts_next->default_action_id = action_id;
1979 : : }
1980 : :
1981 : : /* This last commit stage is simply finalizing a successful commit operation.
1982 : : * This stage is only executed if all the previous stages were successful. This
1983 : : * stage cannot fail.
1984 : : */
1985 : : static void
1986 : 0 : table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1987 : : {
1988 [ # # ]: 0 : struct table *table = &ctl->tables[table_id];
1989 : :
1990 : : /* Move all the pending add entries to the table, as they are now part
1991 : : * of the table.
1992 : : */
1993 : : table_pending_add_admit(table);
1994 : :
1995 : : /* Move all the pending modify1 entries to table, are they are now part
1996 : : * of the table. Free up all the pending modify0 entries, as they are no
1997 : : * longer part of the table.
1998 : : */
1999 : : table_pending_modify1_admit(table);
2000 : 0 : table_pending_modify0_free(table);
2001 : :
2002 : : /* Free up all the pending delete entries, as they are no longer part of
2003 : : * the table.
2004 : : */
2005 : 0 : table_pending_delete_free(table);
2006 : :
2007 : : /* Free up the pending default entry, as it is now part of the table. */
2008 : 0 : table_pending_default_free(table);
2009 : 0 : }
2010 : :
2011 : : /* The rollback stage is only executed when the commit failed, i.e. ANY of the
2012 : : * commit operations that can fail did fail for ANY table. It reverts ALL the
2013 : : * tables to their state before the commit started, as if the commit never
2014 : : * happened.
2015 : : */
2016 : : static void
2017 : 0 : table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2018 : : {
2019 : 0 : struct table *table = &ctl->tables[table_id];
2020 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
2021 : :
2022 [ # # # # ]: 0 : if (table->is_stub || !table_is_update_pending(table, 0))
2023 : : return;
2024 : :
2025 [ # # ]: 0 : if (table->ops.add) {
2026 : : struct rte_swx_table_entry *entry;
2027 : :
2028 : : /* Add back all the entries that were just deleted. */
2029 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
2030 [ # # ]: 0 : if (!table->n_delete)
2031 : : break;
2032 : :
2033 : 0 : table->ops.add(ts_next->obj, entry);
2034 : 0 : table->n_delete--;
2035 : : }
2036 : :
2037 : : /* Add back the old copy for all the entries that were just
2038 : : * modified.
2039 : : */
2040 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2041 [ # # ]: 0 : if (!table->n_modify)
2042 : : break;
2043 : :
2044 : 0 : table->ops.add(ts_next->obj, entry);
2045 : 0 : table->n_modify--;
2046 : : }
2047 : :
2048 : : /* Delete all the entries that were just added. */
2049 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_add, node) {
2050 [ # # ]: 0 : if (!table->n_add)
2051 : : break;
2052 : :
2053 : 0 : table->ops.del(ts_next->obj, entry);
2054 : 0 : table->n_add--;
2055 : : }
2056 : : } else {
2057 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_id];
2058 : :
2059 : : /* Free the new table object, as update was cancelled. */
2060 [ # # # # ]: 0 : if (ts_next->obj && table->ops.free)
2061 : 0 : table->ops.free(ts_next->obj);
2062 : :
2063 : : /* Reinstate the old table object. */
2064 : 0 : ts_next->obj = ts->obj;
2065 : : }
2066 : : }
2067 : :
2068 : : /* This stage is conditionally executed (as instructed by the user) after a
2069 : : * failed commit operation to remove ALL the pending work for ALL the tables.
2070 : : */
2071 : : static void
2072 : 0 : table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2073 : : {
2074 : 0 : struct table *table = &ctl->tables[table_id];
2075 : :
2076 : : /* Free up all the pending add entries, as none of them is part of the
2077 : : * table.
2078 : : */
2079 : 0 : table_pending_add_free(table);
2080 : :
2081 : : /* Free up all the pending modify1 entries, as none of them made it to
2082 : : * the table. Add back all the pending modify0 entries, as none of them
2083 : : * was deleted from the table.
2084 : : */
2085 : 0 : table_pending_modify1_free(table);
2086 : : table_pending_modify0_admit(table);
2087 : :
2088 : : /* Add back all the pending delete entries, as none of them was deleted
2089 : : * from the table.
2090 : : */
2091 : : table_pending_delete_admit(table);
2092 : :
2093 : : /* Free up the pending default entry, as it is no longer going to be
2094 : : * added to the table.
2095 : : */
2096 : 0 : table_pending_default_free(table);
2097 : 0 : }
2098 : :
2099 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_add, 21.08)
2100 : : int
2101 : 0 : rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
2102 : : const char *selector_name,
2103 : : uint32_t *group_id)
2104 : : {
2105 : : struct selector *s;
2106 : : uint32_t i;
2107 : :
2108 : : /* Check input arguments. */
2109 [ # # # # : 0 : if (!ctl || !selector_name || !selector_name[0] || !group_id)
# # ]
2110 : : return -EINVAL;
2111 : :
2112 : 0 : s = selector_find(ctl, selector_name);
2113 [ # # ]: 0 : if (!s)
2114 : : return -EINVAL;
2115 : :
2116 : : /* Find an unused group. */
2117 [ # # ]: 0 : for (i = 0; i < s->info.n_groups_max; i++)
2118 [ # # ]: 0 : if (!s->groups_added[i]) {
2119 : 0 : *group_id = i;
2120 : 0 : s->groups_added[i] = 1;
2121 : 0 : return 0;
2122 : : }
2123 : :
2124 : : return -ENOSPC;
2125 : : }
2126 : :
2127 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_delete, 21.08)
2128 : : int
2129 : 0 : rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2130 : : const char *selector_name,
2131 : : uint32_t group_id)
2132 : : {
2133 : : struct selector *s;
2134 : : struct rte_swx_table_selector_group *group;
2135 : :
2136 : : /* Check input arguments. */
2137 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2138 : : return -EINVAL;
2139 : :
2140 : 0 : s = selector_find(ctl, selector_name);
2141 [ # # ]: 0 : if (!s ||
2142 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2143 [ # # ]: 0 : !s->groups_added[group_id])
2144 : : return -EINVAL;
2145 : :
2146 : : /* Check if this group is already scheduled for deletion. */
2147 [ # # ]: 0 : if (s->groups_pending_delete[group_id])
2148 : : return 0;
2149 : :
2150 : : /* Initialize the pending group, if needed. */
2151 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2152 : : int status;
2153 : :
2154 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2155 [ # # ]: 0 : if (status)
2156 : : return status;
2157 : : }
2158 : :
2159 : 0 : group = s->pending_groups[group_id];
2160 : :
2161 : : /* Schedule removal of all the members from the current group. */
2162 : 0 : for ( ; ; ) {
2163 : : struct rte_swx_table_selector_member *m;
2164 : :
2165 : 0 : m = TAILQ_FIRST(&group->members);
2166 [ # # ]: 0 : if (!m)
2167 : : break;
2168 : :
2169 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
2170 : 0 : free(m);
2171 : : }
2172 : :
2173 : : /* Schedule the group for deletion. */
2174 : 0 : s->groups_pending_delete[group_id] = 1;
2175 : :
2176 : 0 : return 0;
2177 : : }
2178 : :
2179 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_member_add, 21.08)
2180 : : int
2181 : 0 : rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2182 : : const char *selector_name,
2183 : : uint32_t group_id,
2184 : : uint32_t member_id,
2185 : : uint32_t member_weight)
2186 : : {
2187 : : struct selector *s;
2188 : : struct rte_swx_table_selector_group *group;
2189 : : struct rte_swx_table_selector_member *m;
2190 : :
2191 [ # # ]: 0 : if (!member_weight)
2192 : 0 : return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2193 : : selector_name,
2194 : : group_id,
2195 : : member_id);
2196 : :
2197 : : /* Check input arguments. */
2198 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2199 : : return -EINVAL;
2200 : :
2201 : 0 : s = selector_find(ctl, selector_name);
2202 [ # # ]: 0 : if (!s ||
2203 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2204 [ # # ]: 0 : !s->groups_added[group_id] ||
2205 [ # # ]: 0 : s->groups_pending_delete[group_id])
2206 : : return -EINVAL;
2207 : :
2208 : : /* Initialize the pending group, if needed. */
2209 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2210 : : int status;
2211 : :
2212 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2213 [ # # ]: 0 : if (status)
2214 : : return status;
2215 : : }
2216 : :
2217 : 0 : group = s->pending_groups[group_id];
2218 : :
2219 : : /* If this member is already in this group, then simply update its weight and return. */
2220 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node)
2221 [ # # ]: 0 : if (m->member_id == member_id) {
2222 : 0 : m->member_weight = member_weight;
2223 : 0 : return 0;
2224 : : }
2225 : :
2226 : : /* Add new member to this group. */
2227 : 0 : m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2228 [ # # ]: 0 : if (!m)
2229 : : return -ENOMEM;
2230 : :
2231 : 0 : m->member_id = member_id;
2232 : 0 : m->member_weight = member_weight;
2233 : :
2234 : 0 : TAILQ_INSERT_TAIL(&group->members, m, node);
2235 : :
2236 : 0 : return 0;
2237 : : }
2238 : :
2239 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_member_delete, 21.08)
2240 : : int
2241 : 0 : rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2242 : : const char *selector_name,
2243 : : uint32_t group_id __rte_unused,
2244 : : uint32_t member_id __rte_unused)
2245 : : {
2246 : : struct selector *s;
2247 : : struct rte_swx_table_selector_group *group;
2248 : : struct rte_swx_table_selector_member *m;
2249 : :
2250 : : /* Check input arguments. */
2251 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2252 : : return -EINVAL;
2253 : :
2254 : 0 : s = selector_find(ctl, selector_name);
2255 [ # # ]: 0 : if (!s ||
2256 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2257 [ # # ]: 0 : !s->groups_added[group_id] ||
2258 [ # # ]: 0 : s->groups_pending_delete[group_id])
2259 : : return -EINVAL;
2260 : :
2261 : : /* Initialize the pending group, if needed. */
2262 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2263 : : int status;
2264 : :
2265 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2266 [ # # ]: 0 : if (status)
2267 : : return status;
2268 : : }
2269 : :
2270 : 0 : group = s->pending_groups[group_id];
2271 : :
2272 : : /* Look for this member in the group and remove it, if found. */
2273 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node)
2274 [ # # ]: 0 : if (m->member_id == member_id) {
2275 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
2276 : 0 : free(m);
2277 : 0 : return 0;
2278 : : }
2279 : :
2280 : : return 0;
2281 : : }
2282 : :
2283 : : static int
2284 : 0 : selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2285 : : {
2286 : 0 : struct selector *s = &ctl->selectors[selector_id];
2287 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2288 : : uint32_t group_id;
2289 : :
2290 : : /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2291 : : * mirror copy (ts_next->obj).
2292 : : */
2293 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2294 : 0 : struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2295 : : int status;
2296 : :
2297 : : /* Skip this group if no change needed. */
2298 [ # # ]: 0 : if (!group)
2299 : 0 : continue;
2300 : :
2301 : : /* Apply the pending changes for the current group. */
2302 : 0 : status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2303 [ # # ]: 0 : if (status)
2304 : 0 : return status;
2305 : : }
2306 : :
2307 : : return 0;
2308 : : }
2309 : :
2310 : : static void
2311 : 0 : selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2312 : : {
2313 : 0 : struct selector *s = &ctl->selectors[selector_id];
2314 : : uint32_t group_id;
2315 : :
2316 : : /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2317 : : * records (s->groups[group_id).
2318 : : */
2319 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2320 : 0 : struct rte_swx_table_selector_group *g = s->groups[group_id];
2321 : 0 : struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2322 : :
2323 : : /* Skip this group if no change needed. */
2324 [ # # ]: 0 : if (!gp)
2325 : 0 : continue;
2326 : :
2327 : : /* Transition the pending changes to stable. */
2328 : 0 : s->groups[group_id] = gp;
2329 : 0 : s->pending_groups[group_id] = NULL;
2330 : :
2331 : : /* Free the old group member list. */
2332 [ # # ]: 0 : if (!g)
2333 : 0 : continue;
2334 : :
2335 : 0 : for ( ; ; ) {
2336 : : struct rte_swx_table_selector_member *m;
2337 : :
2338 : 0 : m = TAILQ_FIRST(&g->members);
2339 [ # # ]: 0 : if (!m)
2340 : : break;
2341 : :
2342 [ # # ]: 0 : TAILQ_REMOVE(&g->members, m, node);
2343 : 0 : free(m);
2344 : : }
2345 : :
2346 : 0 : free(g);
2347 : : }
2348 : :
2349 : : /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2350 : : * s->groups_added[group_id].
2351 : : */
2352 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2353 [ # # ]: 0 : if (s->groups_pending_delete[group_id]) {
2354 : 0 : s->groups_added[group_id] = 0;
2355 : 0 : s->groups_pending_delete[group_id] = 0;
2356 : : }
2357 : 0 : }
2358 : :
2359 : : static void
2360 : 0 : selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2361 : : {
2362 : 0 : struct selector *s = &ctl->selectors[selector_id];
2363 : 0 : struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2364 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2365 : : uint32_t group_id;
2366 : :
2367 : : /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2368 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2369 : 0 : struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2370 : :
2371 [ # # ]: 0 : if (gp) {
2372 : 0 : ts_next->obj = ts->obj;
2373 : 0 : break;
2374 : : }
2375 : : }
2376 : 0 : }
2377 : :
2378 : : static void
2379 : 0 : selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2380 : : {
2381 : 0 : struct selector *s = &ctl->selectors[selector_id];
2382 : : uint32_t group_id;
2383 : :
2384 : : /* Discard any pending group member changes (s->pending_groups[group_id]). */
2385 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2386 : 0 : selector_pending_group_members_free(s, group_id);
2387 : :
2388 : : /* Discard any pending group deletions. */
2389 : 0 : memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2390 : 0 : }
2391 : :
2392 : : static struct rte_swx_table_entry *
2393 : 0 : learner_default_entry_alloc(struct learner *l)
2394 : : {
2395 : : struct rte_swx_table_entry *entry;
2396 : :
2397 : 0 : entry = calloc(1, sizeof(struct rte_swx_table_entry));
2398 [ # # ]: 0 : if (!entry)
2399 : 0 : goto error;
2400 : :
2401 : : /* action_data. */
2402 [ # # ]: 0 : if (l->action_data_size) {
2403 : 0 : entry->action_data = calloc(1, l->action_data_size);
2404 [ # # ]: 0 : if (!entry->action_data)
2405 : 0 : goto error;
2406 : : }
2407 : :
2408 : : return entry;
2409 : :
2410 : 0 : error:
2411 : 0 : table_entry_free(entry);
2412 : 0 : return NULL;
2413 : : }
2414 : :
2415 : : static int
2416 : 0 : learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2417 : : uint32_t learner_id,
2418 : : struct rte_swx_table_entry *entry)
2419 : : {
2420 : 0 : struct learner *l = &ctl->learners[learner_id];
2421 : : struct action *a;
2422 : : uint32_t i;
2423 : :
2424 [ # # ]: 0 : CHECK(entry, EINVAL);
2425 : :
2426 : : /* action_id. */
2427 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++)
2428 [ # # ]: 0 : if (entry->action_id == l->actions[i].action_id)
2429 : : break;
2430 : :
2431 [ # # ]: 0 : CHECK(i < l->info.n_actions, EINVAL);
2432 : :
2433 : : /* action_data. */
2434 : 0 : a = &ctl->actions[entry->action_id];
2435 [ # # # # ]: 0 : CHECK(!(a->data_size && !entry->action_data), EINVAL);
2436 : :
2437 : : return 0;
2438 : : }
2439 : :
2440 : : static struct rte_swx_table_entry *
2441 : 0 : learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2442 : : uint32_t learner_id,
2443 : : struct rte_swx_table_entry *entry)
2444 : : {
2445 : 0 : struct learner *l = &ctl->learners[learner_id];
2446 : : struct rte_swx_table_entry *new_entry = NULL;
2447 : : struct action *a;
2448 : : uint32_t i;
2449 : :
2450 [ # # ]: 0 : if (!entry)
2451 : 0 : goto error;
2452 : :
2453 : 0 : new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2454 [ # # ]: 0 : if (!new_entry)
2455 : 0 : goto error;
2456 : :
2457 : : /* action_id. */
2458 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++)
2459 [ # # ]: 0 : if (entry->action_id == l->actions[i].action_id)
2460 : : break;
2461 : :
2462 [ # # ]: 0 : if (i >= l->info.n_actions)
2463 : 0 : goto error;
2464 : :
2465 : 0 : new_entry->action_id = entry->action_id;
2466 : :
2467 : : /* action_data. */
2468 : 0 : a = &ctl->actions[entry->action_id];
2469 [ # # # # ]: 0 : if (a->data_size && !entry->action_data)
2470 : 0 : goto error;
2471 : :
2472 : : /* The table layer provisions a constant action data size per
2473 : : * entry, which should be the largest data size for all the
2474 : : * actions enabled for the current table, and attempts to copy
2475 : : * this many bytes each time a table entry is added, even if the
2476 : : * specific action requires less data or even no data at all,
2477 : : * hence we always have to allocate the max.
2478 : : */
2479 : 0 : new_entry->action_data = calloc(1, l->action_data_size);
2480 [ # # ]: 0 : if (!new_entry->action_data)
2481 : 0 : goto error;
2482 : :
2483 [ # # ]: 0 : if (a->data_size)
2484 : 0 : memcpy(new_entry->action_data, entry->action_data, a->data_size);
2485 : :
2486 : : return new_entry;
2487 : :
2488 : 0 : error:
2489 : 0 : table_entry_free(new_entry);
2490 : 0 : return NULL;
2491 : : }
2492 : :
2493 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_learner_default_entry_add, 21.11)
2494 : : int
2495 : 0 : rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2496 : : const char *learner_name,
2497 : : struct rte_swx_table_entry *entry)
2498 : : {
2499 : : struct learner *l;
2500 : : struct rte_swx_table_entry *new_entry;
2501 : : uint32_t learner_id;
2502 : :
2503 [ # # ]: 0 : CHECK(ctl, EINVAL);
2504 : :
2505 [ # # # # ]: 0 : CHECK(learner_name && learner_name[0], EINVAL);
2506 : 0 : l = learner_find(ctl, learner_name);
2507 [ # # ]: 0 : CHECK(l, EINVAL);
2508 : 0 : learner_id = l - ctl->learners;
2509 [ # # ]: 0 : CHECK(!l->info.default_action_is_const, EINVAL);
2510 : :
2511 [ # # ]: 0 : CHECK(entry, EINVAL);
2512 [ # # ]: 0 : CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2513 : :
2514 [ # # ]: 0 : CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2515 : :
2516 : 0 : new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2517 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
2518 : :
2519 : 0 : learner_pending_default_free(l);
2520 : :
2521 : 0 : l->pending_default = new_entry;
2522 : 0 : return 0;
2523 : : }
2524 : :
2525 : : static void
2526 : 0 : learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2527 : : {
2528 : 0 : struct learner *l = &ctl->learners[learner_id];
2529 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2530 : 0 : ctl->info.n_selectors + learner_id];
2531 : : struct action *a;
2532 : : uint8_t *action_data;
2533 : : uint64_t action_id;
2534 : :
2535 : : /* Copy the pending default entry. */
2536 [ # # ]: 0 : if (!l->pending_default)
2537 : : return;
2538 : :
2539 : 0 : action_id = l->pending_default->action_id;
2540 : 0 : action_data = l->pending_default->action_data;
2541 : 0 : a = &ctl->actions[action_id];
2542 : :
2543 [ # # ]: 0 : if (a->data_size)
2544 : 0 : memcpy(ts_next->default_action_data, action_data, a->data_size);
2545 : :
2546 : 0 : ts_next->default_action_id = action_id;
2547 : : }
2548 : :
2549 : : static void
2550 : : learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2551 : : {
2552 : 0 : struct learner *l = &ctl->learners[learner_id];
2553 : :
2554 : : /* Free up the pending default entry, as it is now part of the table. */
2555 : 0 : learner_pending_default_free(l);
2556 : : }
2557 : :
2558 : : static void
2559 : : learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2560 : : {
2561 : 0 : struct learner *l = &ctl->learners[learner_id];
2562 : :
2563 : : /* Free up the pending default entry, as it is no longer going to be added to the table. */
2564 : 0 : learner_pending_default_free(l);
2565 : : }
2566 : :
2567 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_commit, 20.11)
2568 : : int
2569 : 0 : rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2570 : : {
2571 : : struct rte_swx_table_state *ts;
2572 : : int status = 0;
2573 : : uint32_t i;
2574 : :
2575 [ # # ]: 0 : CHECK(ctl, EINVAL);
2576 : :
2577 : : /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2578 : : * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2579 : : * We must be able to fully revert all the changes that can fail as if they never happened.
2580 : : */
2581 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2582 : 0 : status = table_rollfwd0(ctl, i, 0);
2583 [ # # ]: 0 : if (status)
2584 : 0 : goto rollback;
2585 : : }
2586 : :
2587 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2588 : 0 : status = selector_rollfwd(ctl, i);
2589 [ # # ]: 0 : if (status)
2590 : 0 : goto rollback;
2591 : : }
2592 : :
2593 : : /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2594 : : * onwards, the transaction is guaranteed to be successful.
2595 : : */
2596 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++)
2597 : 0 : table_rollfwd1(ctl, i);
2598 : :
2599 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2600 : 0 : learner_rollfwd(ctl, i);
2601 : :
2602 : : /* Swap the table state for the data plane. The current ts and ts_next
2603 : : * become the new ts_next and ts, respectively.
2604 : : */
2605 : 0 : rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2606 : 0 : usleep(100);
2607 : 0 : ts = ctl->ts;
2608 : 0 : ctl->ts = ctl->ts_next;
2609 : 0 : ctl->ts_next = ts;
2610 : :
2611 : : /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2612 : : * the current ts_next in sync with the current ts. Since the changes that can fail did
2613 : : * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2614 : : * current ts_next, hence no error checking is needed.
2615 : : */
2616 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2617 : 0 : table_rollfwd0(ctl, i, 1);
2618 : 0 : table_rollfwd1(ctl, i);
2619 : 0 : table_rollfwd2(ctl, i);
2620 : : }
2621 : :
2622 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2623 : 0 : selector_rollfwd(ctl, i);
2624 : 0 : selector_rollfwd_finalize(ctl, i);
2625 : : }
2626 : :
2627 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
2628 : 0 : learner_rollfwd(ctl, i);
2629 : : learner_rollfwd_finalize(ctl, i);
2630 : : }
2631 : :
2632 : : return 0;
2633 : :
2634 : 0 : rollback:
2635 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2636 : 0 : table_rollback(ctl, i);
2637 [ # # ]: 0 : if (abort_on_fail)
2638 : 0 : table_abort(ctl, i);
2639 : : }
2640 : :
2641 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2642 : 0 : selector_rollback(ctl, i);
2643 [ # # ]: 0 : if (abort_on_fail)
2644 : 0 : selector_abort(ctl, i);
2645 : : }
2646 : :
2647 [ # # ]: 0 : if (abort_on_fail)
2648 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2649 : : learner_abort(ctl, i);
2650 : :
2651 : : return status;
2652 : : }
2653 : :
2654 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_abort, 20.11)
2655 : : void
2656 : 0 : rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2657 : : {
2658 : : uint32_t i;
2659 : :
2660 [ # # ]: 0 : if (!ctl)
2661 : : return;
2662 : :
2663 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++)
2664 : 0 : table_abort(ctl, i);
2665 : :
2666 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++)
2667 : 0 : selector_abort(ctl, i);
2668 : :
2669 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2670 : : learner_abort(ctl, i);
2671 : : }
2672 : :
2673 : : static int
2674 : 0 : mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2675 : : {
2676 : : uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2677 : :
2678 [ # # ]: 0 : if (!mask) {
2679 : 0 : *prefix_length = 0;
2680 : 0 : return 0;
2681 : : }
2682 : :
2683 : : /* Count trailing zero bits. */
2684 [ # # ]: 0 : for (i = 0; i < 64; i++) {
2685 [ # # ]: 0 : if (mask & (1LLU << i))
2686 : : break;
2687 : :
2688 : 0 : n_trailing_zeros++;
2689 : : }
2690 : :
2691 : : /* Count the one bits that follow. */
2692 [ # # ]: 0 : for ( ; i < 64; i++) {
2693 [ # # ]: 0 : if (!(mask & (1LLU << i)))
2694 : : break;
2695 : :
2696 : 0 : n_ones++;
2697 : : }
2698 : :
2699 : : /* Check that no more one bits are present */
2700 [ # # ]: 0 : for ( ; i < 64; i++)
2701 [ # # ]: 0 : if (mask & (1LLU << i))
2702 : : return -EINVAL;
2703 : :
2704 : : /* Check that the input mask is a prefix or the right length. */
2705 [ # # ]: 0 : if (n_ones + n_trailing_zeros != mask_length)
2706 : : return -EINVAL;
2707 : :
2708 : 0 : *prefix_length = n_ones;
2709 : 0 : return 0;
2710 : : }
2711 : :
2712 : : static int
2713 : 0 : large_mask_to_prefix(uint8_t *mask, uint32_t n_mask_bytes, uint32_t *prefix_length)
2714 : : {
2715 : : uint32_t pl, i;
2716 : :
2717 : : /* Check input arguments. */
2718 [ # # # # ]: 0 : if (!mask || !n_mask_bytes || !prefix_length)
2719 : : return -EINVAL;
2720 : :
2721 : : /* Count leading bits of one. */
2722 [ # # ]: 0 : for (i = 0; i < n_mask_bytes * 8; i++) {
2723 : 0 : uint32_t byte_id = i / 8;
2724 : : uint32_t bit_id = i & 7;
2725 : :
2726 : 0 : uint32_t byte = mask[byte_id];
2727 : 0 : uint32_t bit = byte & (1 << (7 - bit_id));
2728 : :
2729 [ # # ]: 0 : if (!bit)
2730 : : break;
2731 : : }
2732 : :
2733 : : /* Save the potential prefix length. */
2734 : : pl = i;
2735 : :
2736 : : /* Check that all remaining bits are zeros. */
2737 [ # # ]: 0 : for ( ; i < n_mask_bytes * 8; i++) {
2738 : 0 : uint32_t byte_id = i / 8;
2739 : : uint32_t bit_id = i & 7;
2740 : :
2741 : 0 : uint32_t byte = mask[byte_id];
2742 : 0 : uint32_t bit = byte & (1 << (7 - bit_id));
2743 : :
2744 [ # # ]: 0 : if (bit)
2745 : : break;
2746 : : }
2747 : :
2748 [ # # ]: 0 : if (i < n_mask_bytes * 8)
2749 : : return -EINVAL;
2750 : :
2751 : 0 : *prefix_length = pl;
2752 : 0 : return 0;
2753 : : }
2754 : :
2755 : : static int
2756 : : char_to_hex(char c, uint8_t *val)
2757 : : {
2758 : 0 : if (c >= '0' && c <= '9') {
2759 : : *val = c - '0';
2760 : : return 0;
2761 : : }
2762 : :
2763 [ # # # # ]: 0 : if (c >= 'A' && c <= 'F') {
2764 : 0 : *val = c - 'A' + 10;
2765 : : return 0;
2766 : : }
2767 : :
2768 [ # # # # ]: 0 : if (c >= 'a' && c <= 'f') {
2769 : 0 : *val = c - 'a' + 10;
2770 : : return 0;
2771 : : }
2772 : :
2773 : : return -EINVAL;
2774 : : }
2775 : :
2776 : : static int
2777 : 0 : hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
2778 : : {
2779 : : uint32_t i;
2780 : :
2781 : : /* Check input arguments. */
2782 [ # # # # : 0 : if (!src || !src[0] || !dst || !n_dst_bytes)
# # ]
2783 : : return -EINVAL;
2784 : :
2785 : : /* Skip any leading "0x" or "0X" in the src string. */
2786 [ # # # # ]: 0 : if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
2787 : 0 : src += 2;
2788 : :
2789 : : /* Convert each group of two hex characters in the src string to one byte in dst array. */
2790 [ # # ]: 0 : for (i = 0; i < n_dst_bytes; i++) {
2791 : : uint8_t a, b;
2792 : : int status;
2793 : :
2794 [ # # ]: 0 : status = char_to_hex(*src, &a);
2795 : : if (status)
2796 : : return status;
2797 : : src++;
2798 : :
2799 [ # # ]: 0 : status = char_to_hex(*src, &b);
2800 : : if (status)
2801 : : return status;
2802 : 0 : src++;
2803 : :
2804 : 0 : dst[i] = a * 16 + b;
2805 : : }
2806 : :
2807 : : /* Check for the end of the src string. */
2808 [ # # ]: 0 : if (*src)
2809 : 0 : return -EINVAL;
2810 : :
2811 : : return 0;
2812 : : }
2813 : :
2814 : : static int
2815 : 0 : table_entry_match_field_read(struct table *table,
2816 : : struct rte_swx_table_entry *entry,
2817 : : uint32_t mf_id,
2818 : : char *mf_val,
2819 : : char *mf_mask,
2820 : : int *lpm,
2821 : : uint32_t *lpm_prefix_length_max,
2822 : : uint32_t *lpm_prefix_length)
2823 : : {
2824 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2825 : 0 : uint64_t val, mask = UINT64_MAX;
2826 : 0 : uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2827 : :
2828 : : /*
2829 : : * Mask.
2830 : : */
2831 [ # # ]: 0 : if (mf_mask) {
2832 : : /* Parse. */
2833 : 0 : mask = strtoull(mf_mask, &mf_mask, 0);
2834 [ # # ]: 0 : if (mf_mask[0])
2835 : : return -EINVAL;
2836 : :
2837 : : /* LPM. */
2838 [ # # ]: 0 : if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2839 : : int status;
2840 : :
2841 : 0 : *lpm = 1;
2842 : :
2843 : 0 : *lpm_prefix_length_max = mf->n_bits;
2844 : :
2845 : 0 : status = mask_to_prefix(mask, mf->n_bits, lpm_prefix_length);
2846 [ # # ]: 0 : if (status)
2847 : : return status;
2848 : : }
2849 : :
2850 : : /* Endianness conversion. */
2851 [ # # ]: 0 : if (mf->is_header)
2852 [ # # ]: 0 : mask = field_hton(mask, mf->n_bits);
2853 : : }
2854 : :
2855 : : /* Copy to entry. */
2856 [ # # ]: 0 : if (entry->key_mask)
2857 : 0 : memcpy(&entry->key_mask[offset], (uint8_t *)&mask, mf->n_bits / 8);
2858 : :
2859 : : /*
2860 : : * Value.
2861 : : */
2862 : : /* Parse. */
2863 : 0 : val = strtoull(mf_val, &mf_val, 0);
2864 [ # # ]: 0 : if (mf_val[0])
2865 : : return -EINVAL;
2866 : :
2867 : : /* Endianness conversion. */
2868 [ # # ]: 0 : if (mf->is_header)
2869 [ # # ]: 0 : val = field_hton(val, mf->n_bits);
2870 : :
2871 : : /* Copy to entry. */
2872 : 0 : memcpy(&entry->key[offset], (uint8_t *)&val, mf->n_bits / 8);
2873 : :
2874 : 0 : return 0;
2875 : : }
2876 : :
2877 : : static int
2878 : 0 : table_entry_action_argument_read(struct action *action,
2879 : : struct rte_swx_table_entry *entry,
2880 : : uint32_t arg_id,
2881 : : uint32_t arg_offset,
2882 : : char *arg_val)
2883 : : {
2884 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2885 : : uint64_t val;
2886 : :
2887 : 0 : val = strtoull(arg_val, &arg_val, 0);
2888 [ # # ]: 0 : if (arg_val[0])
2889 : : return -EINVAL;
2890 : :
2891 : : /* Endianness conversion. */
2892 [ # # ]: 0 : if (arg->is_network_byte_order)
2893 [ # # ]: 0 : val = field_hton(val, arg->n_bits);
2894 : :
2895 : : /* Copy to entry. */
2896 : 0 : memcpy(&entry->action_data[arg_offset],
2897 : : (uint8_t *)&val,
2898 : 0 : arg->n_bits / 8);
2899 : :
2900 : 0 : return 0;
2901 : : }
2902 : :
2903 : : static int
2904 : 0 : table_entry_large_match_field_read(struct table *table,
2905 : : struct rte_swx_table_entry *entry,
2906 : : uint32_t mf_id,
2907 : : char *mf_val,
2908 : : char *mf_mask,
2909 : : int *lpm,
2910 : : uint32_t *lpm_prefix_length_max,
2911 : : uint32_t *lpm_prefix_length)
2912 : : {
2913 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2914 : 0 : uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2915 : : int status;
2916 : :
2917 : : /*
2918 : : * Mask.
2919 : : */
2920 [ # # ]: 0 : if (!entry->key_mask)
2921 : 0 : goto value;
2922 : :
2923 [ # # ]: 0 : if (!mf_mask) {
2924 : : /* Set mask to all-ones. */
2925 : 0 : memset(&entry->key_mask[offset], 0xFF, mf->n_bits / 8);
2926 : 0 : goto value;
2927 : : }
2928 : :
2929 : : /* Parse. */
2930 : 0 : status = hex_string_parse(mf_mask, &entry->key_mask[offset], mf->n_bits / 8);
2931 [ # # ]: 0 : if (status)
2932 : : return -EINVAL;
2933 : :
2934 : : /* LPM. */
2935 [ # # ]: 0 : if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2936 : 0 : *lpm = 1;
2937 : :
2938 : 0 : *lpm_prefix_length_max = mf->n_bits;
2939 : :
2940 : 0 : status = large_mask_to_prefix(&entry->key_mask[offset],
2941 : : mf->n_bits / 8,
2942 : : lpm_prefix_length);
2943 [ # # ]: 0 : if (status)
2944 : : return status;
2945 : : }
2946 : :
2947 : : /*
2948 : : * Value.
2949 : : */
2950 : 0 : value:
2951 : : /* Parse. */
2952 : 0 : status = hex_string_parse(mf_val, &entry->key[offset], mf->n_bits / 8);
2953 [ # # ]: 0 : if (status)
2954 : 0 : return -EINVAL;
2955 : :
2956 : : return 0;
2957 : : }
2958 : :
2959 : : static int
2960 : : table_entry_large_action_argument_read(struct action *action,
2961 : : struct rte_swx_table_entry *entry,
2962 : : uint32_t arg_id,
2963 : : uint32_t arg_offset,
2964 : : char *arg_val)
2965 : : {
2966 : : struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2967 : : int status;
2968 : :
2969 : 0 : status = hex_string_parse(arg_val, &entry->action_data[arg_offset], arg->n_bits / 8);
2970 [ # # ]: 0 : if (status)
2971 : : return -EINVAL;
2972 : :
2973 : : return 0;
2974 : : }
2975 : :
2976 : : static int
2977 : : token_is_comment(const char *token)
2978 : : {
2979 [ # # # # ]: 0 : if ((token[0] == '#') ||
2980 [ # # # # ]: 0 : (token[0] == ';') ||
2981 [ # # # # ]: 0 : ((token[0] == '/') && (token[1] == '/')))
2982 : : return 1; /* TRUE. */
2983 : :
2984 : : return 0; /* FALSE. */
2985 : : }
2986 : :
2987 : : #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2988 : :
2989 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_read, 20.11)
2990 : : struct rte_swx_table_entry *
2991 : 0 : rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2992 : : const char *table_name,
2993 : : const char *string,
2994 : : int *is_blank_or_comment)
2995 : : {
2996 : : char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2997 : : struct table *table;
2998 : : struct action *action;
2999 : : struct rte_swx_table_entry *entry = NULL;
3000 : : char *s0 = NULL, *s;
3001 : 0 : uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
3002 : 0 : int lpm = 0, blank_or_comment = 0;
3003 : :
3004 : : /* Check input arguments. */
3005 [ # # ]: 0 : if (!ctl)
3006 : 0 : goto error;
3007 : :
3008 [ # # # # ]: 0 : if (!table_name || !table_name[0])
3009 : 0 : goto error;
3010 : :
3011 : 0 : table = table_find(ctl, table_name);
3012 [ # # ]: 0 : if (!table)
3013 : 0 : goto error;
3014 : :
3015 [ # # # # ]: 0 : if (!string || !string[0])
3016 : 0 : goto error;
3017 : :
3018 : : /* Memory allocation. */
3019 : 0 : s0 = strdup(string);
3020 [ # # ]: 0 : if (!s0)
3021 : 0 : goto error;
3022 : :
3023 : 0 : entry = table_entry_alloc(table);
3024 [ # # ]: 0 : if (!entry)
3025 : 0 : goto error;
3026 : :
3027 : : /* Parse the string into tokens. */
3028 : 0 : for (s = s0; ; ) {
3029 : : char *token;
3030 : :
3031 : 0 : token = strtok_r(s, " \f\n\r\t\v", &s);
3032 [ # # ]: 0 : if (!token || token_is_comment(token))
3033 : : break;
3034 : :
3035 [ # # ]: 0 : if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3036 : 0 : goto error;
3037 : :
3038 : 0 : token_array[n_tokens] = token;
3039 : 0 : n_tokens++;
3040 : : }
3041 : :
3042 [ # # ]: 0 : if (!n_tokens) {
3043 : : blank_or_comment = 1;
3044 : 0 : goto error;
3045 : : }
3046 : :
3047 : : tokens = token_array;
3048 : :
3049 : : /*
3050 : : * Match.
3051 : : */
3052 [ # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "match")))
3053 : 0 : goto action;
3054 : :
3055 [ # # ]: 0 : if (n_tokens < 1 + table->info.n_match_fields)
3056 : 0 : goto error;
3057 : :
3058 [ # # ]: 0 : for (i = 0; i < table->info.n_match_fields; i++) {
3059 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
3060 : 0 : char *mf_val = tokens[1 + i], *mf_mask = NULL;
3061 : : int status;
3062 : :
3063 : 0 : mf_mask = strchr(mf_val, '/');
3064 [ # # ]: 0 : if (mf_mask) {
3065 : 0 : *mf_mask = 0;
3066 : 0 : mf_mask++;
3067 : : }
3068 : :
3069 [ # # ]: 0 : if (mf->n_bits <= 64)
3070 : 0 : status = table_entry_match_field_read(table,
3071 : : entry,
3072 : : i,
3073 : : mf_val,
3074 : : mf_mask,
3075 : : &lpm,
3076 : : &lpm_prefix_length_max,
3077 : : &lpm_prefix_length);
3078 : : else
3079 : 0 : status = table_entry_large_match_field_read(table,
3080 : : entry,
3081 : : i,
3082 : : mf_val,
3083 : : mf_mask,
3084 : : &lpm,
3085 : : &lpm_prefix_length_max,
3086 : : &lpm_prefix_length);
3087 [ # # ]: 0 : if (status)
3088 : 0 : goto error;
3089 : :
3090 : : }
3091 : :
3092 : 0 : tokens += 1 + table->info.n_match_fields;
3093 : 0 : n_tokens -= 1 + table->info.n_match_fields;
3094 : :
3095 : : /*
3096 : : * Match priority.
3097 : : */
3098 [ # # # # ]: 0 : if (n_tokens && !strcmp(tokens[0], "priority")) {
3099 : 0 : char *priority = tokens[1];
3100 : : uint32_t val;
3101 : :
3102 [ # # ]: 0 : if (n_tokens < 2)
3103 : 0 : goto error;
3104 : :
3105 : : /* Parse. */
3106 : 0 : val = strtoul(priority, &priority, 0);
3107 [ # # ]: 0 : if (priority[0])
3108 : 0 : goto error;
3109 : :
3110 : : /* Copy to entry. */
3111 : 0 : entry->key_priority = val;
3112 : :
3113 : 0 : tokens += 2;
3114 : 0 : n_tokens -= 2;
3115 : : }
3116 : :
3117 : : /* LPM. */
3118 [ # # ]: 0 : if (lpm)
3119 : 0 : entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
3120 : :
3121 : : /*
3122 : : * Action.
3123 : : */
3124 : 0 : action:
3125 [ # # # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "action")))
3126 : 0 : goto other;
3127 : :
3128 [ # # ]: 0 : if (n_tokens < 2)
3129 : 0 : goto error;
3130 : :
3131 : 0 : action = action_find(ctl, tokens[1]);
3132 [ # # ]: 0 : if (!action)
3133 : 0 : goto error;
3134 : :
3135 [ # # ]: 0 : if (n_tokens < 2 + action->info.n_args * 2)
3136 : 0 : goto error;
3137 : :
3138 : : /* action_id. */
3139 : 0 : entry->action_id = action - ctl->actions;
3140 : :
3141 : : /* action_data. */
3142 [ # # ]: 0 : for (i = 0; i < action->info.n_args; i++) {
3143 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3144 : : char *arg_name, *arg_val;
3145 : : int status;
3146 : :
3147 : 0 : arg_name = tokens[2 + i * 2];
3148 : 0 : arg_val = tokens[2 + i * 2 + 1];
3149 : :
3150 [ # # ]: 0 : if (strcmp(arg_name, arg->name))
3151 : 0 : goto error;
3152 : :
3153 [ # # ]: 0 : if (arg->n_bits <= 64)
3154 : 0 : status = table_entry_action_argument_read(action,
3155 : : entry,
3156 : : i,
3157 : : arg_offset,
3158 : : arg_val);
3159 : : else
3160 : : status = table_entry_large_action_argument_read(action,
3161 : : entry,
3162 : : i,
3163 : : arg_offset,
3164 : : arg_val);
3165 [ # # ]: 0 : if (status)
3166 : 0 : goto error;
3167 : :
3168 : 0 : arg_offset += arg->n_bits / 8;
3169 : : }
3170 : :
3171 : 0 : tokens += 2 + action->info.n_args * 2;
3172 : 0 : n_tokens -= 2 + action->info.n_args * 2;
3173 : :
3174 : 0 : other:
3175 [ # # ]: 0 : if (n_tokens)
3176 : 0 : goto error;
3177 : :
3178 : 0 : free(s0);
3179 : 0 : return entry;
3180 : :
3181 : 0 : error:
3182 : 0 : table_entry_free(entry);
3183 : 0 : free(s0);
3184 [ # # ]: 0 : if (is_blank_or_comment)
3185 : 0 : *is_blank_or_comment = blank_or_comment;
3186 : : return NULL;
3187 : : }
3188 : :
3189 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_learner_default_entry_read, 21.11)
3190 : : struct rte_swx_table_entry *
3191 : 0 : rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
3192 : : const char *learner_name,
3193 : : const char *string,
3194 : : int *is_blank_or_comment)
3195 : : {
3196 : : char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
3197 : : struct learner *l;
3198 : : struct action *action;
3199 : : struct rte_swx_table_entry *entry = NULL;
3200 : : char *s0 = NULL, *s;
3201 : : uint32_t n_tokens = 0, arg_offset = 0, i;
3202 : : int blank_or_comment = 0;
3203 : :
3204 : : /* Check input arguments. */
3205 [ # # ]: 0 : if (!ctl)
3206 : 0 : goto error;
3207 : :
3208 [ # # # # ]: 0 : if (!learner_name || !learner_name[0])
3209 : 0 : goto error;
3210 : :
3211 : 0 : l = learner_find(ctl, learner_name);
3212 [ # # ]: 0 : if (!l)
3213 : 0 : goto error;
3214 : :
3215 [ # # # # ]: 0 : if (!string || !string[0])
3216 : 0 : goto error;
3217 : :
3218 : : /* Memory allocation. */
3219 : 0 : s0 = strdup(string);
3220 [ # # ]: 0 : if (!s0)
3221 : 0 : goto error;
3222 : :
3223 : 0 : entry = learner_default_entry_alloc(l);
3224 [ # # ]: 0 : if (!entry)
3225 : 0 : goto error;
3226 : :
3227 : : /* Parse the string into tokens. */
3228 : 0 : for (s = s0; ; ) {
3229 : : char *token;
3230 : :
3231 : 0 : token = strtok_r(s, " \f\n\r\t\v", &s);
3232 [ # # ]: 0 : if (!token || token_is_comment(token))
3233 : : break;
3234 : :
3235 [ # # ]: 0 : if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3236 : 0 : goto error;
3237 : :
3238 : 0 : token_array[n_tokens] = token;
3239 : 0 : n_tokens++;
3240 : : }
3241 : :
3242 [ # # ]: 0 : if (!n_tokens) {
3243 : : blank_or_comment = 1;
3244 : 0 : goto error;
3245 : : }
3246 : :
3247 : : tokens = token_array;
3248 : :
3249 : : /*
3250 : : * Action.
3251 : : */
3252 [ # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "action")))
3253 : 0 : goto other;
3254 : :
3255 [ # # ]: 0 : if (n_tokens < 2)
3256 : 0 : goto error;
3257 : :
3258 : 0 : action = action_find(ctl, tokens[1]);
3259 [ # # ]: 0 : if (!action)
3260 : 0 : goto error;
3261 : :
3262 [ # # ]: 0 : if (n_tokens < 2 + action->info.n_args * 2)
3263 : 0 : goto error;
3264 : :
3265 : : /* action_id. */
3266 : 0 : entry->action_id = action - ctl->actions;
3267 : :
3268 : : /* action_data. */
3269 [ # # ]: 0 : for (i = 0; i < action->info.n_args; i++) {
3270 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3271 : : char *arg_name, *arg_val;
3272 : : uint64_t val;
3273 : :
3274 : 0 : arg_name = tokens[2 + i * 2];
3275 : 0 : arg_val = tokens[2 + i * 2 + 1];
3276 : :
3277 [ # # ]: 0 : if (strcmp(arg_name, arg->name))
3278 : 0 : goto error;
3279 : :
3280 : 0 : val = strtoull(arg_val, &arg_val, 0);
3281 [ # # ]: 0 : if (arg_val[0])
3282 : 0 : goto error;
3283 : :
3284 : : /* Endianness conversion. */
3285 [ # # ]: 0 : if (arg->is_network_byte_order)
3286 [ # # ]: 0 : val = field_hton(val, arg->n_bits);
3287 : :
3288 : : /* Copy to entry. */
3289 : 0 : memcpy(&entry->action_data[arg_offset],
3290 : : (uint8_t *)&val,
3291 : 0 : arg->n_bits / 8);
3292 : :
3293 : 0 : arg_offset += arg->n_bits / 8;
3294 : : }
3295 : :
3296 : 0 : tokens += 2 + action->info.n_args * 2;
3297 : 0 : n_tokens -= 2 + action->info.n_args * 2;
3298 : :
3299 : 0 : other:
3300 [ # # ]: 0 : if (n_tokens)
3301 : 0 : goto error;
3302 : :
3303 : 0 : free(s0);
3304 : 0 : return entry;
3305 : :
3306 : 0 : error:
3307 : 0 : table_entry_free(entry);
3308 : 0 : free(s0);
3309 [ # # ]: 0 : if (is_blank_or_comment)
3310 : 0 : *is_blank_or_comment = blank_or_comment;
3311 : : return NULL;
3312 : : }
3313 : :
3314 : : static void
3315 : 0 : table_entry_printf(FILE *f,
3316 : : struct rte_swx_ctl_pipeline *ctl,
3317 : : struct table *table,
3318 : : struct rte_swx_table_entry *entry)
3319 : : {
3320 : 0 : struct action *action = &ctl->actions[entry->action_id];
3321 : : uint32_t i;
3322 : :
3323 : : fprintf(f, "match ");
3324 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3325 : 0 : fprintf(f, "%02x", entry->key[i]);
3326 : :
3327 [ # # ]: 0 : if (entry->key_mask) {
3328 : : fprintf(f, "/");
3329 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3330 : 0 : fprintf(f, "%02x", entry->key_mask[i]);
3331 : : }
3332 : :
3333 : 0 : fprintf(f, " priority %u", entry->key_priority);
3334 : :
3335 : 0 : fprintf(f, " action %s ", action->info.name);
3336 [ # # ]: 0 : for (i = 0; i < action->data_size; i++)
3337 : 0 : fprintf(f, "%02x", entry->action_data[i]);
3338 : :
3339 : : fprintf(f, "\n");
3340 : 0 : }
3341 : :
3342 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_fprintf, 20.11)
3343 : : int
3344 : 0 : rte_swx_ctl_pipeline_table_fprintf(FILE *f,
3345 : : struct rte_swx_ctl_pipeline *ctl,
3346 : : const char *table_name)
3347 : : {
3348 : : struct table *table;
3349 : : struct rte_swx_table_entry *entry;
3350 : : uint32_t n_entries = 0, i;
3351 : :
3352 [ # # # # : 0 : if (!f || !ctl || !table_name || !table_name[0])
# # ]
3353 : : return -EINVAL;
3354 : :
3355 : 0 : table = table_find(ctl, table_name);
3356 [ # # ]: 0 : if (!table)
3357 : : return -EINVAL;
3358 : :
3359 : : /* Table. */
3360 : 0 : fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3361 : 0 : table->info.name,
3362 : : table->params.key_size,
3363 : : table->params.key_offset);
3364 : :
3365 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3366 : 0 : fprintf(f, "%02x", table->params.key_mask0[i]);
3367 : :
3368 : 0 : fprintf(f, "], action data size %u bytes\n",
3369 : : table->params.action_data_size);
3370 : :
3371 : : /* Table entries. */
3372 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->entries, node) {
3373 : 0 : table_entry_printf(f, ctl, table, entry);
3374 : 0 : n_entries++;
3375 : : }
3376 : :
3377 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3378 : 0 : table_entry_printf(f, ctl, table, entry);
3379 : 0 : n_entries++;
3380 : : }
3381 : :
3382 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
3383 : 0 : table_entry_printf(f, ctl, table, entry);
3384 : 0 : n_entries++;
3385 : : }
3386 : :
3387 : : fprintf(f, "# Table %s currently has %u entries.\n",
3388 : : table_name,
3389 : : n_entries);
3390 : 0 : return 0;
3391 : : }
3392 : :
3393 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_fprintf, 21.08)
3394 : : int
3395 : 0 : rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3396 : : struct rte_swx_ctl_pipeline *ctl,
3397 : : const char *selector_name)
3398 : : {
3399 : : struct selector *s;
3400 : : uint32_t group_id;
3401 : :
3402 [ # # # # : 0 : if (!f || !ctl || !selector_name || !selector_name[0])
# # ]
3403 : : return -EINVAL;
3404 : :
3405 : 0 : s = selector_find(ctl, selector_name);
3406 [ # # ]: 0 : if (!s)
3407 : : return -EINVAL;
3408 : :
3409 : : /* Selector. */
3410 : 0 : fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3411 : 0 : s->info.name,
3412 : : s->info.n_groups_max,
3413 : : s->info.n_members_per_group_max);
3414 : :
3415 : : /* Groups. */
3416 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3417 : 0 : struct rte_swx_table_selector_group *group = s->groups[group_id];
3418 : : struct rte_swx_table_selector_member *m;
3419 : : uint32_t n_members = 0;
3420 : :
3421 : : fprintf(f, "Group %u = [", group_id);
3422 : :
3423 : : /* Non-empty group. */
3424 [ # # ]: 0 : if (group)
3425 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node) {
3426 : 0 : fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3427 : 0 : n_members++;
3428 : : }
3429 : :
3430 : : /* Empty group. */
3431 [ # # ]: 0 : if (!n_members)
3432 : : fprintf(f, "0:1 ");
3433 : :
3434 : : fprintf(f, "]\n");
3435 : : }
3436 : :
3437 : : return 0;
3438 : : }
|