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, i;
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 : : memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
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 : : uint32_t i;
859 : :
860 : : /* selector_fields. */
861 : 0 : free(s->selector_fields);
862 : :
863 : : /* groups. */
864 [ # # ]: 0 : if (s->groups)
865 [ # # ]: 0 : for (i = 0; i < s->info.n_groups_max; i++)
866 : 0 : selector_group_members_free(s, i);
867 : :
868 : 0 : free(s->groups);
869 : :
870 : : /* pending_groups. */
871 [ # # ]: 0 : if (s->pending_groups)
872 [ # # ]: 0 : for (i = 0; i < s->info.n_groups_max; i++)
873 : 0 : selector_pending_group_members_free(s, i);
874 : :
875 : 0 : free(s->pending_groups);
876 : :
877 : : /* groups_added. */
878 : 0 : free(s->groups_added);
879 : :
880 : : /* groups_pending_delete. */
881 : 0 : free(s->groups_pending_delete);
882 : :
883 : : /* params. */
884 : 0 : free(s->params.selector_mask);
885 : : }
886 : :
887 : 0 : free(ctl->selectors);
888 : 0 : ctl->selectors = NULL;
889 : : }
890 : :
891 : : static struct selector *
892 : 0 : selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
893 : : {
894 : : uint32_t i;
895 : :
896 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
897 : 0 : struct selector *s = &ctl->selectors[i];
898 : :
899 [ # # ]: 0 : if (!strcmp(selector_name, s->info.name))
900 : 0 : return s;
901 : : }
902 : :
903 : : return NULL;
904 : : }
905 : :
906 : : static int
907 : 0 : selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
908 : : {
909 : 0 : struct selector *s = &ctl->selectors[selector_id];
910 : : struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
911 : : uint8_t *selector_mask = NULL;
912 : : uint32_t selector_size = 0, selector_offset = 0, i;
913 : :
914 : : /* Find first (smallest offset) and last (biggest offset) match fields. */
915 : 0 : first = &s->selector_fields[0];
916 : : last = &s->selector_fields[0];
917 : :
918 [ # # ]: 0 : for (i = 1; i < s->info.n_selector_fields; i++) {
919 : 0 : struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
920 : :
921 [ # # ]: 0 : if (f->offset < first->offset)
922 : : first = f;
923 : :
924 [ # # ]: 0 : if (f->offset > last->offset)
925 : : last = f;
926 : : }
927 : :
928 : : /* selector_offset. */
929 : 0 : selector_offset = first->offset / 8;
930 : :
931 : : /* selector_size. */
932 : 0 : selector_size = (last->offset + last->n_bits - first->offset) / 8;
933 : :
934 : : /* selector_mask. */
935 : 0 : selector_mask = calloc(1, selector_size);
936 [ # # ]: 0 : if (!selector_mask)
937 : : return -ENOMEM;
938 : :
939 [ # # ]: 0 : for (i = 0; i < s->info.n_selector_fields; i++) {
940 : 0 : struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
941 : : uint32_t start;
942 : : size_t size;
943 : :
944 : 0 : start = (f->offset - first->offset) / 8;
945 : 0 : size = f->n_bits / 8;
946 : :
947 : 0 : memset(&selector_mask[start], 0xFF, size);
948 : : }
949 : :
950 : : /* Fill in. */
951 : 0 : s->params.group_id_offset = s->group_id_field.offset / 8;
952 : 0 : s->params.selector_size = selector_size;
953 : 0 : s->params.selector_offset = selector_offset;
954 : 0 : s->params.selector_mask = selector_mask;
955 : 0 : s->params.member_id_offset = s->member_id_field.offset / 8;
956 : 0 : s->params.n_groups_max = s->info.n_groups_max;
957 : 0 : s->params.n_members_per_group_max = s->info.n_members_per_group_max;
958 : :
959 : 0 : return 0;
960 : : }
961 : :
962 : : static void
963 : 0 : learner_pending_default_free(struct learner *l)
964 : : {
965 [ # # ]: 0 : if (!l->pending_default)
966 : : return;
967 : :
968 : 0 : free(l->pending_default->action_data);
969 : 0 : free(l->pending_default);
970 : 0 : l->pending_default = NULL;
971 : : }
972 : :
973 : :
974 : : static void
975 : 0 : learner_free(struct rte_swx_ctl_pipeline *ctl)
976 : : {
977 : : uint32_t i;
978 : :
979 [ # # ]: 0 : if (!ctl->learners)
980 : : return;
981 : :
982 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
983 : 0 : struct learner *l = &ctl->learners[i];
984 : :
985 : 0 : free(l->mf);
986 : 0 : free(l->actions);
987 : :
988 : 0 : learner_pending_default_free(l);
989 : : }
990 : :
991 : 0 : free(ctl->learners);
992 : 0 : ctl->learners = NULL;
993 : : }
994 : :
995 : : static struct learner *
996 : 0 : learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
997 : : {
998 : : uint32_t i;
999 : :
1000 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1001 : 0 : struct learner *l = &ctl->learners[i];
1002 : :
1003 [ # # ]: 0 : if (!strcmp(learner_name, l->info.name))
1004 : 0 : return l;
1005 : : }
1006 : :
1007 : : return NULL;
1008 : : }
1009 : :
1010 : : static uint32_t
1011 : : learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1012 : : {
1013 : : uint32_t action_data_size = 0, i;
1014 : :
1015 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++) {
1016 : 0 : uint32_t action_id = l->actions[i].action_id;
1017 : 0 : struct action *a = &ctl->actions[action_id];
1018 : :
1019 : 0 : if (a->data_size > action_data_size)
1020 : : action_data_size = a->data_size;
1021 : : }
1022 : :
1023 : : return action_data_size;
1024 : : }
1025 : :
1026 : : static void
1027 : 0 : table_state_free(struct rte_swx_ctl_pipeline *ctl)
1028 : : {
1029 : : uint32_t table_base_index, selector_base_index, learner_base_index, i;
1030 : :
1031 [ # # ]: 0 : if (!ctl->ts_next)
1032 : : return;
1033 : :
1034 : : /* For each table, free its table state. */
1035 : : table_base_index = 0;
1036 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1037 : 0 : struct table *table = &ctl->tables[i];
1038 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
1039 : :
1040 : : /* Default action data. */
1041 : 0 : free(ts->default_action_data);
1042 : :
1043 : : /* Table object. */
1044 [ # # # # : 0 : if (!table->is_stub && table->ops.free && ts->obj)
# # ]
1045 : 0 : table->ops.free(ts->obj);
1046 : : }
1047 : :
1048 : : /* For each selector table, free its table state. */
1049 : : selector_base_index = ctl->info.n_tables;
1050 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1051 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1052 : :
1053 : : /* Table object. */
1054 : 0 : rte_swx_table_selector_free(ts->obj);
1055 : : }
1056 : :
1057 : : /* For each learner table, free its table state. */
1058 : 0 : learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1059 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1060 : 0 : struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1061 : :
1062 : : /* Default action data. */
1063 : 0 : free(ts->default_action_data);
1064 : : }
1065 : :
1066 : 0 : free(ctl->ts_next);
1067 : 0 : ctl->ts_next = NULL;
1068 : : }
1069 : :
1070 : : static int
1071 : 0 : table_state_create(struct rte_swx_ctl_pipeline *ctl)
1072 : : {
1073 : : uint32_t table_base_index, selector_base_index, learner_base_index, i;
1074 : : int status = 0;
1075 : :
1076 : 0 : ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1077 : : sizeof(struct rte_swx_table_state));
1078 [ # # ]: 0 : if (!ctl->ts_next) {
1079 : : status = -ENOMEM;
1080 : 0 : goto error;
1081 : : }
1082 : :
1083 : : /* Tables. */
1084 : : table_base_index = 0;
1085 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1086 : 0 : struct table *table = &ctl->tables[i];
1087 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1088 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1089 : :
1090 : : /* Table object. */
1091 [ # # # # ]: 0 : if (!table->is_stub && table->ops.add) {
1092 : 0 : ts_next->obj = table->ops.create(&table->params,
1093 : : &table->entries,
1094 : 0 : table->info.args,
1095 : : ctl->numa_node);
1096 [ # # ]: 0 : if (!ts_next->obj) {
1097 : : status = -ENODEV;
1098 : 0 : goto error;
1099 : : }
1100 : : }
1101 : :
1102 [ # # # # ]: 0 : if (!table->is_stub && !table->ops.add)
1103 : 0 : ts_next->obj = ts->obj;
1104 : :
1105 : : /* Default action data: duplicate from current table state. */
1106 : 0 : ts_next->default_action_data =
1107 : 0 : malloc(table->params.action_data_size);
1108 [ # # ]: 0 : if (!ts_next->default_action_data) {
1109 : : status = -ENOMEM;
1110 : 0 : goto error;
1111 : : }
1112 : :
1113 : : memcpy(ts_next->default_action_data,
1114 : 0 : ts->default_action_data,
1115 : : table->params.action_data_size);
1116 : :
1117 : 0 : ts_next->default_action_id = ts->default_action_id;
1118 : : }
1119 : :
1120 : : /* Selector tables. */
1121 : : selector_base_index = ctl->info.n_tables;
1122 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1123 : 0 : struct selector *s = &ctl->selectors[i];
1124 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1125 : :
1126 : : /* Table object. */
1127 : 0 : ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1128 [ # # ]: 0 : if (!ts_next->obj) {
1129 : : status = -ENODEV;
1130 : 0 : goto error;
1131 : : }
1132 : : }
1133 : :
1134 : : /* Learner tables. */
1135 : 0 : learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1136 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1137 : 0 : struct learner *l = &ctl->learners[i];
1138 : 0 : struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1139 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1140 : :
1141 : : /* Table object: duplicate from the current table state. */
1142 : 0 : ts_next->obj = ts->obj;
1143 : :
1144 : : /* Default action data: duplicate from the current table state. */
1145 : 0 : ts_next->default_action_data = malloc(l->action_data_size);
1146 [ # # ]: 0 : if (!ts_next->default_action_data) {
1147 : : status = -ENOMEM;
1148 : 0 : goto error;
1149 : : }
1150 : :
1151 : : memcpy(ts_next->default_action_data,
1152 : 0 : ts->default_action_data,
1153 : : l->action_data_size);
1154 : :
1155 : 0 : ts_next->default_action_id = ts->default_action_id;
1156 : : }
1157 : :
1158 : : return 0;
1159 : :
1160 : 0 : error:
1161 : 0 : table_state_free(ctl);
1162 : 0 : return status;
1163 : : }
1164 : :
1165 : : /* Global list of pipeline instances. */
1166 : : TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
1167 : :
1168 : : static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
1169 : : .name = "RTE_SWX_CTL_PIPELINE",
1170 : : };
1171 : :
1172 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
1173 : :
1174 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_find, 22.11)
1175 : : struct rte_swx_ctl_pipeline *
1176 : 0 : rte_swx_ctl_pipeline_find(const char *name)
1177 : : {
1178 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1179 : : struct rte_tailq_entry *te = NULL;
1180 : :
1181 [ # # # # : 0 : if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
# # ]
1182 : : return NULL;
1183 : :
1184 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1185 : :
1186 : 0 : rte_mcfg_tailq_read_lock();
1187 : :
1188 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1189 : 0 : struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
1190 : :
1191 [ # # ]: 0 : if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
1192 : 0 : rte_mcfg_tailq_read_unlock();
1193 : 0 : return ctl;
1194 : : }
1195 : : }
1196 : :
1197 : 0 : rte_mcfg_tailq_read_unlock();
1198 : 0 : return NULL;
1199 : : }
1200 : :
1201 : : static int
1202 : 0 : ctl_register(struct rte_swx_ctl_pipeline *ctl)
1203 : : {
1204 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1205 : : struct rte_tailq_entry *te = NULL;
1206 : :
1207 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1208 : :
1209 : 0 : rte_mcfg_tailq_write_lock();
1210 : :
1211 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1212 : 0 : struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
1213 : :
1214 [ # # ]: 0 : if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
1215 : 0 : rte_mcfg_tailq_write_unlock();
1216 : 0 : return -EEXIST;
1217 : : }
1218 : : }
1219 : :
1220 : 0 : te = calloc(1, sizeof(struct rte_tailq_entry));
1221 [ # # ]: 0 : if (!te) {
1222 : 0 : rte_mcfg_tailq_write_unlock();
1223 : 0 : return -ENOMEM;
1224 : : }
1225 : :
1226 : 0 : te->data = (void *)ctl;
1227 : 0 : TAILQ_INSERT_TAIL(ctl_list, te, next);
1228 : 0 : rte_mcfg_tailq_write_unlock();
1229 : 0 : return 0;
1230 : : }
1231 : :
1232 : : static void
1233 : 0 : ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
1234 : : {
1235 : : struct rte_swx_ctl_pipeline_list *ctl_list;
1236 : : struct rte_tailq_entry *te = NULL;
1237 : :
1238 : 0 : ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1239 : :
1240 : 0 : rte_mcfg_tailq_write_lock();
1241 : :
1242 [ # # ]: 0 : TAILQ_FOREACH(te, ctl_list, next) {
1243 [ # # ]: 0 : if (te->data == (void *)ctl) {
1244 [ # # ]: 0 : TAILQ_REMOVE(ctl_list, te, next);
1245 : 0 : rte_mcfg_tailq_write_unlock();
1246 : 0 : free(te);
1247 : 0 : return;
1248 : : }
1249 : : }
1250 : :
1251 : 0 : rte_mcfg_tailq_write_unlock();
1252 : : }
1253 : :
1254 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_free, 20.11)
1255 : : void
1256 : 0 : rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1257 : : {
1258 [ # # ]: 0 : if (!ctl)
1259 : : return;
1260 : :
1261 [ # # ]: 0 : if (ctl->info.name[0])
1262 : 0 : ctl_unregister(ctl);
1263 : :
1264 : 0 : action_free(ctl);
1265 : :
1266 : 0 : table_state_free(ctl);
1267 : :
1268 : 0 : learner_free(ctl);
1269 : :
1270 : 0 : selector_free(ctl);
1271 : :
1272 : 0 : table_free(ctl);
1273 : :
1274 : 0 : free(ctl);
1275 : : }
1276 : :
1277 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_create, 20.11)
1278 : : struct rte_swx_ctl_pipeline *
1279 : 0 : rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1280 : : {
1281 : : struct rte_swx_ctl_pipeline *ctl = NULL;
1282 : : uint32_t i;
1283 : : int status;
1284 : :
1285 [ # # ]: 0 : if (!p)
1286 : 0 : goto error;
1287 : :
1288 : 0 : ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1289 [ # # ]: 0 : if (!ctl)
1290 : 0 : goto error;
1291 : :
1292 : : /* info. */
1293 : 0 : status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1294 [ # # ]: 0 : if (status)
1295 : 0 : goto error;
1296 : :
1297 : : /* numa_node. */
1298 : 0 : status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1299 [ # # ]: 0 : if (status)
1300 : 0 : goto error;
1301 : :
1302 : : /* p. */
1303 : 0 : ctl->p = p;
1304 : :
1305 : : /* actions. */
1306 : 0 : ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1307 [ # # ]: 0 : if (!ctl->actions)
1308 : 0 : goto error;
1309 : :
1310 [ # # ]: 0 : for (i = 0; i < ctl->info.n_actions; i++) {
1311 : 0 : struct action *a = &ctl->actions[i];
1312 : : uint32_t j;
1313 : :
1314 : : /* info. */
1315 : 0 : status = rte_swx_ctl_action_info_get(p, i, &a->info);
1316 [ # # ]: 0 : if (status)
1317 : 0 : goto error;
1318 : :
1319 : : /* args. */
1320 : 0 : a->args = calloc(a->info.n_args,
1321 : : sizeof(struct rte_swx_ctl_action_arg_info));
1322 [ # # ]: 0 : if (!a->args)
1323 : 0 : goto error;
1324 : :
1325 [ # # ]: 0 : for (j = 0; j < a->info.n_args; j++) {
1326 : 0 : status = rte_swx_ctl_action_arg_info_get(p,
1327 : : i,
1328 : : j,
1329 : 0 : &a->args[j]);
1330 [ # # ]: 0 : if (status)
1331 : 0 : goto error;
1332 : : }
1333 : :
1334 : : /* data_size. */
1335 [ # # ]: 0 : for (j = 0; j < a->info.n_args; j++) {
1336 : 0 : struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1337 : :
1338 : 0 : a->data_size += info->n_bits;
1339 : : }
1340 : :
1341 : 0 : a->data_size = (a->data_size + 7) / 8;
1342 : : }
1343 : :
1344 : : /* tables. */
1345 : 0 : ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1346 [ # # ]: 0 : if (!ctl->tables)
1347 : 0 : goto error;
1348 : :
1349 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1350 : 0 : struct table *t = &ctl->tables[i];
1351 : :
1352 : 0 : TAILQ_INIT(&t->entries);
1353 : 0 : TAILQ_INIT(&t->pending_add);
1354 : 0 : TAILQ_INIT(&t->pending_modify0);
1355 : 0 : TAILQ_INIT(&t->pending_modify1);
1356 : 0 : TAILQ_INIT(&t->pending_delete);
1357 : : }
1358 : :
1359 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
1360 : 0 : struct table *t = &ctl->tables[i];
1361 : : uint32_t j;
1362 : :
1363 : : /* info. */
1364 : 0 : status = rte_swx_ctl_table_info_get(p, i, &t->info);
1365 [ # # ]: 0 : if (status)
1366 : 0 : goto error;
1367 : :
1368 : : /* mf. */
1369 : 0 : t->mf = calloc(t->info.n_match_fields,
1370 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1371 [ # # ]: 0 : if (!t->mf)
1372 : 0 : goto error;
1373 : :
1374 [ # # ]: 0 : for (j = 0; j < t->info.n_match_fields; j++) {
1375 : 0 : status = rte_swx_ctl_table_match_field_info_get(p,
1376 : : i,
1377 : : j,
1378 : 0 : &t->mf[j]);
1379 [ # # ]: 0 : if (status)
1380 : 0 : goto error;
1381 : : }
1382 : :
1383 : : /* actions. */
1384 : 0 : t->actions = calloc(t->info.n_actions,
1385 : : sizeof(struct rte_swx_ctl_table_action_info));
1386 [ # # ]: 0 : if (!t->actions)
1387 : 0 : goto error;
1388 : :
1389 [ # # ]: 0 : for (j = 0; j < t->info.n_actions; j++) {
1390 : 0 : status = rte_swx_ctl_table_action_info_get(p,
1391 : : i,
1392 : : j,
1393 : 0 : &t->actions[j]);
1394 [ # # ]: 0 : if (status ||
1395 [ # # ]: 0 : t->actions[j].action_id >= ctl->info.n_actions)
1396 : 0 : goto error;
1397 : : }
1398 : :
1399 : : /* ops, is_stub. */
1400 : 0 : status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1401 [ # # ]: 0 : if (status)
1402 : 0 : goto error;
1403 : :
1404 [ # # # # : 0 : if ((t->is_stub && t->info.n_match_fields) ||
# # ]
1405 [ # # ]: 0 : (!t->is_stub && !t->info.n_match_fields))
1406 : 0 : goto error;
1407 : :
1408 : : /* params. */
1409 : 0 : status = table_params_get(ctl, i);
1410 [ # # ]: 0 : if (status)
1411 : 0 : goto error;
1412 : : }
1413 : :
1414 : : /* selector tables. */
1415 : 0 : ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1416 [ # # ]: 0 : if (!ctl->selectors)
1417 : 0 : goto error;
1418 : :
1419 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
1420 : 0 : struct selector *s = &ctl->selectors[i];
1421 : : uint32_t j;
1422 : :
1423 : : /* info. */
1424 : 0 : status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1425 [ # # ]: 0 : if (status)
1426 : 0 : goto error;
1427 : :
1428 : : /* group_id field. */
1429 : 0 : status = rte_swx_ctl_selector_group_id_field_info_get(p,
1430 : : i,
1431 : : &s->group_id_field);
1432 [ # # ]: 0 : if (status)
1433 : 0 : goto error;
1434 : :
1435 : : /* selector fields. */
1436 : 0 : s->selector_fields = calloc(s->info.n_selector_fields,
1437 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1438 [ # # ]: 0 : if (!s->selector_fields)
1439 : 0 : goto error;
1440 : :
1441 [ # # ]: 0 : for (j = 0; j < s->info.n_selector_fields; j++) {
1442 : 0 : status = rte_swx_ctl_selector_field_info_get(p,
1443 : : i,
1444 : : j,
1445 : 0 : &s->selector_fields[j]);
1446 [ # # ]: 0 : if (status)
1447 : 0 : goto error;
1448 : : }
1449 : :
1450 : : /* member_id field. */
1451 : 0 : status = rte_swx_ctl_selector_member_id_field_info_get(p,
1452 : : i,
1453 : : &s->member_id_field);
1454 [ # # ]: 0 : if (status)
1455 : 0 : goto error;
1456 : :
1457 : : /* groups. */
1458 : 0 : s->groups = calloc(s->info.n_groups_max,
1459 : : sizeof(struct rte_swx_table_selector_group *));
1460 [ # # ]: 0 : if (!s->groups)
1461 : 0 : goto error;
1462 : :
1463 : : /* pending_groups. */
1464 : 0 : s->pending_groups = calloc(s->info.n_groups_max,
1465 : : sizeof(struct rte_swx_table_selector_group *));
1466 [ # # ]: 0 : if (!s->pending_groups)
1467 : 0 : goto error;
1468 : :
1469 : : /* groups_added. */
1470 : 0 : s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1471 [ # # ]: 0 : if (!s->groups_added)
1472 : 0 : goto error;
1473 : :
1474 : : /* groups_pending_delete. */
1475 : 0 : s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1476 [ # # ]: 0 : if (!s->groups_pending_delete)
1477 : 0 : goto error;
1478 : :
1479 : : /* params. */
1480 : 0 : status = selector_params_get(ctl, i);
1481 [ # # ]: 0 : if (status)
1482 : 0 : goto error;
1483 : : }
1484 : :
1485 : : /* learner tables. */
1486 : 0 : ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1487 [ # # ]: 0 : if (!ctl->learners)
1488 : 0 : goto error;
1489 : :
1490 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
1491 : 0 : struct learner *l = &ctl->learners[i];
1492 : : uint32_t j;
1493 : :
1494 : : /* info. */
1495 : 0 : status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1496 [ # # ]: 0 : if (status)
1497 : 0 : goto error;
1498 : :
1499 : : /* mf. */
1500 : 0 : l->mf = calloc(l->info.n_match_fields,
1501 : : sizeof(struct rte_swx_ctl_table_match_field_info));
1502 [ # # ]: 0 : if (!l->mf)
1503 : 0 : goto error;
1504 : :
1505 [ # # ]: 0 : for (j = 0; j < l->info.n_match_fields; j++) {
1506 : 0 : status = rte_swx_ctl_learner_match_field_info_get(p,
1507 : : i,
1508 : : j,
1509 : 0 : &l->mf[j]);
1510 [ # # ]: 0 : if (status)
1511 : 0 : goto error;
1512 : : }
1513 : :
1514 : : /* actions. */
1515 : 0 : l->actions = calloc(l->info.n_actions,
1516 : : sizeof(struct rte_swx_ctl_table_action_info));
1517 [ # # ]: 0 : if (!l->actions)
1518 : 0 : goto error;
1519 : :
1520 [ # # ]: 0 : for (j = 0; j < l->info.n_actions; j++) {
1521 : 0 : status = rte_swx_ctl_learner_action_info_get(p,
1522 : : i,
1523 : : j,
1524 : 0 : &l->actions[j]);
1525 [ # # # # ]: 0 : if (status || l->actions[j].action_id >= ctl->info.n_actions)
1526 : 0 : goto error;
1527 : : }
1528 : :
1529 : : /* action_data_size. */
1530 : 0 : l->action_data_size = learner_action_data_size_get(ctl, l);
1531 : : }
1532 : :
1533 : : /* ts. */
1534 : 0 : status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1535 [ # # ]: 0 : if (status)
1536 : 0 : goto error;
1537 : :
1538 : : /* ts_next. */
1539 : 0 : status = table_state_create(ctl);
1540 [ # # ]: 0 : if (status)
1541 : 0 : goto error;
1542 : :
1543 [ # # ]: 0 : if (ctl->info.name[0]) {
1544 : 0 : status = ctl_register(ctl);
1545 [ # # ]: 0 : if (status)
1546 : 0 : goto error;
1547 : : }
1548 : :
1549 : : return ctl;
1550 : :
1551 : 0 : error:
1552 : 0 : rte_swx_ctl_pipeline_free(ctl);
1553 : 0 : return NULL;
1554 : : }
1555 : :
1556 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_add, 20.11)
1557 : : int
1558 : 0 : rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1559 : : const char *table_name,
1560 : : struct rte_swx_table_entry *entry)
1561 : : {
1562 : : struct table *table;
1563 : : struct rte_swx_table_entry *new_entry, *existing_entry;
1564 : : uint32_t table_id;
1565 : :
1566 [ # # ]: 0 : CHECK(ctl, EINVAL);
1567 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1568 : :
1569 : 0 : table = table_find(ctl, table_name);
1570 [ # # ]: 0 : CHECK(table, EINVAL);
1571 : 0 : table_id = table - ctl->tables;
1572 : :
1573 [ # # ]: 0 : CHECK(entry, EINVAL);
1574 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1575 : :
1576 : 0 : new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1577 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
1578 : :
1579 : : /* The new entry is found in the table->entries list:
1580 : : * - Add the new entry to the table->pending_modify1 list;
1581 : : * - Move the existing entry from the table->entries list to the
1582 : : * table->pending_modify0 list.
1583 : : */
1584 : : existing_entry = table_entries_find(table, entry);
1585 [ # # ]: 0 : if (existing_entry) {
1586 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify1,
1587 : : new_entry,
1588 : : node);
1589 : :
1590 [ # # ]: 0 : TAILQ_REMOVE(&table->entries,
1591 : : existing_entry,
1592 : : node);
1593 : :
1594 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify0,
1595 : : existing_entry,
1596 : : node);
1597 : :
1598 : 0 : return 0;
1599 : : }
1600 : :
1601 : : /* The new entry is found in the table->pending_add list:
1602 : : * - Replace the entry in the table->pending_add list with the new entry
1603 : : * (and free the replaced entry).
1604 : : */
1605 : : existing_entry = table_pending_add_find(table, entry);
1606 [ # # ]: 0 : if (existing_entry) {
1607 [ # # ]: 0 : TAILQ_INSERT_AFTER(&table->pending_add,
1608 : : existing_entry,
1609 : : new_entry,
1610 : : node);
1611 : :
1612 : 0 : TAILQ_REMOVE(&table->pending_add,
1613 : : existing_entry,
1614 : : node);
1615 : :
1616 : 0 : table_entry_free(existing_entry);
1617 : :
1618 : 0 : return 0;
1619 : : }
1620 : :
1621 : : /* The new entry is found in the table->pending_modify1 list:
1622 : : * - Replace the entry in the table->pending_modify1 list with the new
1623 : : * entry (and free the replaced entry).
1624 : : */
1625 : : existing_entry = table_pending_modify1_find(table, entry);
1626 [ # # ]: 0 : if (existing_entry) {
1627 [ # # ]: 0 : TAILQ_INSERT_AFTER(&table->pending_modify1,
1628 : : existing_entry,
1629 : : new_entry,
1630 : : node);
1631 : :
1632 : 0 : TAILQ_REMOVE(&table->pending_modify1,
1633 : : existing_entry,
1634 : : node);
1635 : :
1636 : 0 : table_entry_free(existing_entry);
1637 : :
1638 : 0 : return 0;
1639 : : }
1640 : :
1641 : : /* The new entry is found in the table->pending_delete list:
1642 : : * - Add the new entry to the table->pending_modify1 list;
1643 : : * - Move the existing entry from the table->pending_delete list to the
1644 : : * table->pending_modify0 list.
1645 : : */
1646 : : existing_entry = table_pending_delete_find(table, entry);
1647 [ # # ]: 0 : if (existing_entry) {
1648 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify1,
1649 : : new_entry,
1650 : : node);
1651 : :
1652 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_delete,
1653 : : existing_entry,
1654 : : node);
1655 : :
1656 : 0 : TAILQ_INSERT_TAIL(&table->pending_modify0,
1657 : : existing_entry,
1658 : : node);
1659 : :
1660 : 0 : return 0;
1661 : : }
1662 : :
1663 : : /* The new entry is not found in any of the above lists:
1664 : : * - Add the new entry to the table->pending_add list.
1665 : : */
1666 : 0 : TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1667 : :
1668 : 0 : return 0;
1669 : : }
1670 : :
1671 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_delete, 20.11)
1672 : : int
1673 : 0 : rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1674 : : const char *table_name,
1675 : : struct rte_swx_table_entry *entry)
1676 : : {
1677 : : struct table *table;
1678 : : struct rte_swx_table_entry *existing_entry;
1679 : : uint32_t table_id;
1680 : :
1681 [ # # ]: 0 : CHECK(ctl, EINVAL);
1682 : :
1683 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1684 : 0 : table = table_find(ctl, table_name);
1685 [ # # ]: 0 : CHECK(table, EINVAL);
1686 : 0 : table_id = table - ctl->tables;
1687 : :
1688 [ # # ]: 0 : CHECK(entry, EINVAL);
1689 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1690 : :
1691 : : /* The entry is found in the table->entries list:
1692 : : * - Move the existing entry from the table->entries list to the
1693 : : * table->pending_delete list.
1694 : : */
1695 : : existing_entry = table_entries_find(table, entry);
1696 [ # # ]: 0 : if (existing_entry) {
1697 [ # # ]: 0 : TAILQ_REMOVE(&table->entries,
1698 : : existing_entry,
1699 : : node);
1700 : :
1701 : 0 : TAILQ_INSERT_TAIL(&table->pending_delete,
1702 : : existing_entry,
1703 : : node);
1704 : :
1705 : 0 : return 0;
1706 : : }
1707 : :
1708 : : /* The entry is found in the table->pending_add list:
1709 : : * - Remove the entry from the table->pending_add list and free it.
1710 : : */
1711 : : existing_entry = table_pending_add_find(table, entry);
1712 [ # # ]: 0 : if (existing_entry) {
1713 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_add,
1714 : : existing_entry,
1715 : : node);
1716 : :
1717 : 0 : table_entry_free(existing_entry);
1718 : : }
1719 : :
1720 : : /* The entry is found in the table->pending_modify1 list:
1721 : : * - Free the entry in the table->pending_modify1 list;
1722 : : * - Move the existing entry from the table->pending_modify0 list to the
1723 : : * table->pending_delete list.
1724 : : */
1725 : : existing_entry = table_pending_modify1_find(table, entry);
1726 [ # # ]: 0 : if (existing_entry) {
1727 : : struct rte_swx_table_entry *real_existing_entry;
1728 : :
1729 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify1,
1730 : : existing_entry,
1731 : : node);
1732 : :
1733 : 0 : table_entry_free(existing_entry);
1734 : :
1735 : : real_existing_entry = table_pending_modify0_find(table, entry);
1736 [ # # ]: 0 : CHECK(real_existing_entry, EINVAL); /* Coverity. */
1737 : :
1738 [ # # ]: 0 : TAILQ_REMOVE(&table->pending_modify0,
1739 : : real_existing_entry,
1740 : : node);
1741 : :
1742 : 0 : TAILQ_INSERT_TAIL(&table->pending_delete,
1743 : : real_existing_entry,
1744 : : node);
1745 : :
1746 : 0 : return 0;
1747 : : }
1748 : :
1749 : : /* The entry is found in the table->pending_delete list:
1750 : : * - Do nothing: the existing entry is already in the
1751 : : * table->pending_delete list, i.e. already marked for delete, so
1752 : : * simply keep it there as it is.
1753 : : */
1754 : :
1755 : : /* The entry is not found in any of the above lists:
1756 : : * - Do nothing: no existing entry to delete.
1757 : : */
1758 : :
1759 : : return 0;
1760 : : }
1761 : :
1762 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_default_entry_add, 20.11)
1763 : : int
1764 : 0 : rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1765 : : const char *table_name,
1766 : : struct rte_swx_table_entry *entry)
1767 : : {
1768 : : struct table *table;
1769 : : struct rte_swx_table_entry *new_entry;
1770 : : uint32_t table_id;
1771 : :
1772 [ # # ]: 0 : CHECK(ctl, EINVAL);
1773 : :
1774 [ # # # # ]: 0 : CHECK(table_name && table_name[0], EINVAL);
1775 : 0 : table = table_find(ctl, table_name);
1776 [ # # ]: 0 : CHECK(table, EINVAL);
1777 : 0 : table_id = table - ctl->tables;
1778 [ # # ]: 0 : CHECK(!table->info.default_action_is_const, EINVAL);
1779 : :
1780 [ # # ]: 0 : CHECK(entry, EINVAL);
1781 [ # # ]: 0 : CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1782 : :
1783 : 0 : new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1784 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
1785 : :
1786 : 0 : table_pending_default_free(table);
1787 : :
1788 : 0 : table->pending_default = new_entry;
1789 : 0 : return 0;
1790 : : }
1791 : :
1792 : :
1793 : : static void
1794 : 0 : table_entry_list_free(struct rte_swx_table_entry_list *list)
1795 : : {
1796 : 0 : for ( ; ; ) {
1797 : : struct rte_swx_table_entry *entry;
1798 : :
1799 : 0 : entry = TAILQ_FIRST(list);
1800 [ # # ]: 0 : if (!entry)
1801 : : break;
1802 : :
1803 [ # # ]: 0 : TAILQ_REMOVE(list, entry, node);
1804 : 0 : table_entry_free(entry);
1805 : : }
1806 : 0 : }
1807 : :
1808 : : static int
1809 : 0 : table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1810 : : uint32_t table_id,
1811 : : struct rte_swx_table_entry_list *dst,
1812 : : struct rte_swx_table_entry_list *src)
1813 : : {
1814 : : struct rte_swx_table_entry *src_entry;
1815 : :
1816 [ # # ]: 0 : TAILQ_FOREACH(src_entry, src, node) {
1817 : : struct rte_swx_table_entry *dst_entry;
1818 : :
1819 : 0 : dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1820 [ # # ]: 0 : if (!dst_entry)
1821 : 0 : goto error;
1822 : :
1823 : 0 : TAILQ_INSERT_TAIL(dst, dst_entry, node);
1824 : : }
1825 : :
1826 : : return 0;
1827 : :
1828 : : error:
1829 : 0 : table_entry_list_free(dst);
1830 : 0 : return -ENOMEM;
1831 : : }
1832 : :
1833 : : /* This commit stage contains all the operations that can fail; in case ANY of
1834 : : * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1835 : : */
1836 : : static int
1837 : 0 : table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1838 : : uint32_t table_id,
1839 : : uint32_t after_swap)
1840 : : {
1841 : 0 : struct table *table = &ctl->tables[table_id];
1842 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_id];
1843 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1844 : :
1845 [ # # # # ]: 0 : if (table->is_stub || !table_is_update_pending(table, 0))
1846 : : return 0;
1847 : :
1848 : : /*
1849 : : * Current table supports incremental update.
1850 : : */
1851 [ # # ]: 0 : if (table->ops.add) {
1852 : : /* Reset counters. */
1853 : 0 : table->n_add = 0;
1854 : 0 : table->n_modify = 0;
1855 : 0 : table->n_delete = 0;
1856 : :
1857 : : /* Add pending rules. */
1858 : : struct rte_swx_table_entry *entry;
1859 : :
1860 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_add, node) {
1861 : : int status;
1862 : :
1863 : 0 : status = table->ops.add(ts_next->obj, entry);
1864 [ # # ]: 0 : if (status)
1865 : 0 : return status;
1866 : :
1867 : 0 : table->n_add++;
1868 : : }
1869 : :
1870 : : /* Modify pending rules. */
1871 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1872 : : int status;
1873 : :
1874 : 0 : status = table->ops.add(ts_next->obj, entry);
1875 [ # # ]: 0 : if (status)
1876 : 0 : return status;
1877 : :
1878 : 0 : table->n_modify++;
1879 : : }
1880 : :
1881 : : /* Delete pending rules. */
1882 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
1883 : : int status;
1884 : :
1885 : 0 : status = table->ops.del(ts_next->obj, entry);
1886 [ # # ]: 0 : if (status)
1887 : 0 : return status;
1888 : :
1889 : 0 : table->n_delete++;
1890 : : }
1891 : :
1892 : : return 0;
1893 : : }
1894 : :
1895 : : /*
1896 : : * Current table does NOT support incremental update.
1897 : : */
1898 [ # # ]: 0 : if (!after_swap) {
1899 : : struct rte_swx_table_entry_list list;
1900 : : int status;
1901 : :
1902 : : /* Create updated list of entries included. */
1903 : 0 : TAILQ_INIT(&list);
1904 : :
1905 : 0 : status = table_entry_list_duplicate(ctl,
1906 : : table_id,
1907 : : &list,
1908 : : &table->entries);
1909 [ # # ]: 0 : if (status)
1910 : 0 : goto error;
1911 : :
1912 : 0 : status = table_entry_list_duplicate(ctl,
1913 : : table_id,
1914 : : &list,
1915 : : &table->pending_add);
1916 [ # # ]: 0 : if (status)
1917 : 0 : goto error;
1918 : :
1919 : 0 : status = table_entry_list_duplicate(ctl,
1920 : : table_id,
1921 : : &list,
1922 : : &table->pending_modify1);
1923 [ # # ]: 0 : if (status)
1924 : 0 : goto error;
1925 : :
1926 : : /* Create new table object with the updates included. */
1927 : 0 : ts_next->obj = table->ops.create(&table->params,
1928 : : &list,
1929 : 0 : table->info.args,
1930 : : ctl->numa_node);
1931 [ # # ]: 0 : if (!ts_next->obj) {
1932 : : status = -ENODEV;
1933 : 0 : goto error;
1934 : : }
1935 : :
1936 : 0 : table_entry_list_free(&list);
1937 : :
1938 : 0 : return 0;
1939 : :
1940 : 0 : error:
1941 : 0 : table_entry_list_free(&list);
1942 : 0 : return status;
1943 : : }
1944 : :
1945 : : /* Free the old table object. */
1946 [ # # # # ]: 0 : if (ts_next->obj && table->ops.free)
1947 : 0 : table->ops.free(ts_next->obj);
1948 : :
1949 : : /* Copy over the new table object. */
1950 : 0 : ts_next->obj = ts->obj;
1951 : :
1952 : 0 : return 0;
1953 : : }
1954 : :
1955 : : /* This commit stage contains all the operations that cannot fail. They are
1956 : : * executed only if the previous stage was successful for ALL the tables. Hence,
1957 : : * none of these operations has to be rolled back for ANY table.
1958 : : */
1959 : : static void
1960 : 0 : table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1961 : : {
1962 : 0 : struct table *table = &ctl->tables[table_id];
1963 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1964 : : struct action *a;
1965 : : uint8_t *action_data;
1966 : : uint64_t action_id;
1967 : :
1968 : : /* Copy the pending default entry. */
1969 [ # # ]: 0 : if (!table->pending_default)
1970 : : return;
1971 : :
1972 : 0 : action_id = table->pending_default->action_id;
1973 : 0 : action_data = table->pending_default->action_data;
1974 : 0 : a = &ctl->actions[action_id];
1975 : :
1976 [ # # ]: 0 : if (a->data_size)
1977 : 0 : memcpy(ts_next->default_action_data, action_data, a->data_size);
1978 : :
1979 : 0 : ts_next->default_action_id = action_id;
1980 : : }
1981 : :
1982 : : /* This last commit stage is simply finalizing a successful commit operation.
1983 : : * This stage is only executed if all the previous stages were successful. This
1984 : : * stage cannot fail.
1985 : : */
1986 : : static void
1987 : 0 : table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1988 : : {
1989 [ # # ]: 0 : struct table *table = &ctl->tables[table_id];
1990 : :
1991 : : /* Move all the pending add entries to the table, as they are now part
1992 : : * of the table.
1993 : : */
1994 : : table_pending_add_admit(table);
1995 : :
1996 : : /* Move all the pending modify1 entries to table, are they are now part
1997 : : * of the table. Free up all the pending modify0 entries, as they are no
1998 : : * longer part of the table.
1999 : : */
2000 : : table_pending_modify1_admit(table);
2001 : 0 : table_pending_modify0_free(table);
2002 : :
2003 : : /* Free up all the pending delete entries, as they are no longer part of
2004 : : * the table.
2005 : : */
2006 : 0 : table_pending_delete_free(table);
2007 : :
2008 : : /* Free up the pending default entry, as it is now part of the table. */
2009 : 0 : table_pending_default_free(table);
2010 : 0 : }
2011 : :
2012 : : /* The rollback stage is only executed when the commit failed, i.e. ANY of the
2013 : : * commit operations that can fail did fail for ANY table. It reverts ALL the
2014 : : * tables to their state before the commit started, as if the commit never
2015 : : * happened.
2016 : : */
2017 : : static void
2018 : 0 : table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2019 : : {
2020 : 0 : struct table *table = &ctl->tables[table_id];
2021 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
2022 : :
2023 [ # # # # ]: 0 : if (table->is_stub || !table_is_update_pending(table, 0))
2024 : : return;
2025 : :
2026 [ # # ]: 0 : if (table->ops.add) {
2027 : : struct rte_swx_table_entry *entry;
2028 : :
2029 : : /* Add back all the entries that were just deleted. */
2030 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
2031 [ # # ]: 0 : if (!table->n_delete)
2032 : : break;
2033 : :
2034 : 0 : table->ops.add(ts_next->obj, entry);
2035 : 0 : table->n_delete--;
2036 : : }
2037 : :
2038 : : /* Add back the old copy for all the entries that were just
2039 : : * modified.
2040 : : */
2041 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2042 [ # # ]: 0 : if (!table->n_modify)
2043 : : break;
2044 : :
2045 : 0 : table->ops.add(ts_next->obj, entry);
2046 : 0 : table->n_modify--;
2047 : : }
2048 : :
2049 : : /* Delete all the entries that were just added. */
2050 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_add, node) {
2051 [ # # ]: 0 : if (!table->n_add)
2052 : : break;
2053 : :
2054 : 0 : table->ops.del(ts_next->obj, entry);
2055 : 0 : table->n_add--;
2056 : : }
2057 : : } else {
2058 : 0 : struct rte_swx_table_state *ts = &ctl->ts[table_id];
2059 : :
2060 : : /* Free the new table object, as update was cancelled. */
2061 [ # # # # ]: 0 : if (ts_next->obj && table->ops.free)
2062 : 0 : table->ops.free(ts_next->obj);
2063 : :
2064 : : /* Reinstate the old table object. */
2065 : 0 : ts_next->obj = ts->obj;
2066 : : }
2067 : : }
2068 : :
2069 : : /* This stage is conditionally executed (as instructed by the user) after a
2070 : : * failed commit operation to remove ALL the pending work for ALL the tables.
2071 : : */
2072 : : static void
2073 : 0 : table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2074 : : {
2075 : 0 : struct table *table = &ctl->tables[table_id];
2076 : :
2077 : : /* Free up all the pending add entries, as none of them is part of the
2078 : : * table.
2079 : : */
2080 : 0 : table_pending_add_free(table);
2081 : :
2082 : : /* Free up all the pending modify1 entries, as none of them made it to
2083 : : * the table. Add back all the pending modify0 entries, as none of them
2084 : : * was deleted from the table.
2085 : : */
2086 : 0 : table_pending_modify1_free(table);
2087 : : table_pending_modify0_admit(table);
2088 : :
2089 : : /* Add back all the pending delete entries, as none of them was deleted
2090 : : * from the table.
2091 : : */
2092 : : table_pending_delete_admit(table);
2093 : :
2094 : : /* Free up the pending default entry, as it is no longer going to be
2095 : : * added to the table.
2096 : : */
2097 : 0 : table_pending_default_free(table);
2098 : 0 : }
2099 : :
2100 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_add, 21.08)
2101 : : int
2102 : 0 : rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
2103 : : const char *selector_name,
2104 : : uint32_t *group_id)
2105 : : {
2106 : : struct selector *s;
2107 : : uint32_t i;
2108 : :
2109 : : /* Check input arguments. */
2110 [ # # # # : 0 : if (!ctl || !selector_name || !selector_name[0] || !group_id)
# # ]
2111 : : return -EINVAL;
2112 : :
2113 : 0 : s = selector_find(ctl, selector_name);
2114 [ # # ]: 0 : if (!s)
2115 : : return -EINVAL;
2116 : :
2117 : : /* Find an unused group. */
2118 [ # # ]: 0 : for (i = 0; i < s->info.n_groups_max; i++)
2119 [ # # ]: 0 : if (!s->groups_added[i]) {
2120 : 0 : *group_id = i;
2121 : 0 : s->groups_added[i] = 1;
2122 : 0 : return 0;
2123 : : }
2124 : :
2125 : : return -ENOSPC;
2126 : : }
2127 : :
2128 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_delete, 21.08)
2129 : : int
2130 : 0 : rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2131 : : const char *selector_name,
2132 : : uint32_t group_id)
2133 : : {
2134 : : struct selector *s;
2135 : : struct rte_swx_table_selector_group *group;
2136 : :
2137 : : /* Check input arguments. */
2138 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2139 : : return -EINVAL;
2140 : :
2141 : 0 : s = selector_find(ctl, selector_name);
2142 [ # # ]: 0 : if (!s ||
2143 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2144 [ # # ]: 0 : !s->groups_added[group_id])
2145 : : return -EINVAL;
2146 : :
2147 : : /* Check if this group is already scheduled for deletion. */
2148 [ # # ]: 0 : if (s->groups_pending_delete[group_id])
2149 : : return 0;
2150 : :
2151 : : /* Initialize the pending group, if needed. */
2152 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2153 : : int status;
2154 : :
2155 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2156 [ # # ]: 0 : if (status)
2157 : : return status;
2158 : : }
2159 : :
2160 : 0 : group = s->pending_groups[group_id];
2161 : :
2162 : : /* Schedule removal of all the members from the current group. */
2163 : 0 : for ( ; ; ) {
2164 : : struct rte_swx_table_selector_member *m;
2165 : :
2166 : 0 : m = TAILQ_FIRST(&group->members);
2167 [ # # ]: 0 : if (!m)
2168 : : break;
2169 : :
2170 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
2171 : 0 : free(m);
2172 : : }
2173 : :
2174 : : /* Schedule the group for deletion. */
2175 : 0 : s->groups_pending_delete[group_id] = 1;
2176 : :
2177 : 0 : return 0;
2178 : : }
2179 : :
2180 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_member_add, 21.08)
2181 : : int
2182 : 0 : rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2183 : : const char *selector_name,
2184 : : uint32_t group_id,
2185 : : uint32_t member_id,
2186 : : uint32_t member_weight)
2187 : : {
2188 : : struct selector *s;
2189 : : struct rte_swx_table_selector_group *group;
2190 : : struct rte_swx_table_selector_member *m;
2191 : :
2192 [ # # ]: 0 : if (!member_weight)
2193 : 0 : return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2194 : : selector_name,
2195 : : group_id,
2196 : : member_id);
2197 : :
2198 : : /* Check input arguments. */
2199 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2200 : : return -EINVAL;
2201 : :
2202 : 0 : s = selector_find(ctl, selector_name);
2203 [ # # ]: 0 : if (!s ||
2204 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2205 [ # # ]: 0 : !s->groups_added[group_id] ||
2206 [ # # ]: 0 : s->groups_pending_delete[group_id])
2207 : : return -EINVAL;
2208 : :
2209 : : /* Initialize the pending group, if needed. */
2210 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2211 : : int status;
2212 : :
2213 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2214 [ # # ]: 0 : if (status)
2215 : : return status;
2216 : : }
2217 : :
2218 : 0 : group = s->pending_groups[group_id];
2219 : :
2220 : : /* If this member is already in this group, then simply update its weight and return. */
2221 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node)
2222 [ # # ]: 0 : if (m->member_id == member_id) {
2223 : 0 : m->member_weight = member_weight;
2224 : 0 : return 0;
2225 : : }
2226 : :
2227 : : /* Add new member to this group. */
2228 : 0 : m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2229 [ # # ]: 0 : if (!m)
2230 : : return -ENOMEM;
2231 : :
2232 : 0 : m->member_id = member_id;
2233 : 0 : m->member_weight = member_weight;
2234 : :
2235 : 0 : TAILQ_INSERT_TAIL(&group->members, m, node);
2236 : :
2237 : 0 : return 0;
2238 : : }
2239 : :
2240 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_group_member_delete, 21.08)
2241 : : int
2242 : 0 : rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2243 : : const char *selector_name,
2244 : : uint32_t group_id __rte_unused,
2245 : : uint32_t member_id __rte_unused)
2246 : : {
2247 : : struct selector *s;
2248 : : struct rte_swx_table_selector_group *group;
2249 : : struct rte_swx_table_selector_member *m;
2250 : :
2251 : : /* Check input arguments. */
2252 [ # # # # ]: 0 : if (!ctl || !selector_name || !selector_name[0])
2253 : : return -EINVAL;
2254 : :
2255 : 0 : s = selector_find(ctl, selector_name);
2256 [ # # ]: 0 : if (!s ||
2257 [ # # ]: 0 : (group_id >= s->info.n_groups_max) ||
2258 [ # # ]: 0 : !s->groups_added[group_id] ||
2259 [ # # ]: 0 : s->groups_pending_delete[group_id])
2260 : : return -EINVAL;
2261 : :
2262 : : /* Initialize the pending group, if needed. */
2263 [ # # ]: 0 : if (!s->pending_groups[group_id]) {
2264 : : int status;
2265 : :
2266 : 0 : status = selector_group_duplicate_to_pending(s, group_id);
2267 [ # # ]: 0 : if (status)
2268 : : return status;
2269 : : }
2270 : :
2271 : 0 : group = s->pending_groups[group_id];
2272 : :
2273 : : /* Look for this member in the group and remove it, if found. */
2274 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node)
2275 [ # # ]: 0 : if (m->member_id == member_id) {
2276 [ # # ]: 0 : TAILQ_REMOVE(&group->members, m, node);
2277 : 0 : free(m);
2278 : 0 : return 0;
2279 : : }
2280 : :
2281 : : return 0;
2282 : : }
2283 : :
2284 : : static int
2285 : 0 : selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2286 : : {
2287 : 0 : struct selector *s = &ctl->selectors[selector_id];
2288 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2289 : : uint32_t group_id;
2290 : :
2291 : : /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2292 : : * mirror copy (ts_next->obj).
2293 : : */
2294 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2295 : 0 : struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2296 : : int status;
2297 : :
2298 : : /* Skip this group if no change needed. */
2299 [ # # ]: 0 : if (!group)
2300 : 0 : continue;
2301 : :
2302 : : /* Apply the pending changes for the current group. */
2303 : 0 : status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2304 [ # # ]: 0 : if (status)
2305 : 0 : return status;
2306 : : }
2307 : :
2308 : : return 0;
2309 : : }
2310 : :
2311 : : static void
2312 : 0 : selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2313 : : {
2314 : 0 : struct selector *s = &ctl->selectors[selector_id];
2315 : : uint32_t group_id;
2316 : :
2317 : : /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2318 : : * records (s->groups[group_id).
2319 : : */
2320 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2321 : 0 : struct rte_swx_table_selector_group *g = s->groups[group_id];
2322 : 0 : struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2323 : :
2324 : : /* Skip this group if no change needed. */
2325 [ # # ]: 0 : if (!gp)
2326 : 0 : continue;
2327 : :
2328 : : /* Transition the pending changes to stable. */
2329 : 0 : s->groups[group_id] = gp;
2330 : 0 : s->pending_groups[group_id] = NULL;
2331 : :
2332 : : /* Free the old group member list. */
2333 [ # # ]: 0 : if (!g)
2334 : 0 : continue;
2335 : :
2336 : 0 : for ( ; ; ) {
2337 : : struct rte_swx_table_selector_member *m;
2338 : :
2339 : 0 : m = TAILQ_FIRST(&g->members);
2340 [ # # ]: 0 : if (!m)
2341 : : break;
2342 : :
2343 [ # # ]: 0 : TAILQ_REMOVE(&g->members, m, node);
2344 : 0 : free(m);
2345 : : }
2346 : :
2347 : 0 : free(g);
2348 : : }
2349 : :
2350 : : /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2351 : : * s->groups_added[group_id].
2352 : : */
2353 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2354 [ # # ]: 0 : if (s->groups_pending_delete[group_id]) {
2355 : 0 : s->groups_added[group_id] = 0;
2356 : 0 : s->groups_pending_delete[group_id] = 0;
2357 : : }
2358 : 0 : }
2359 : :
2360 : : static void
2361 : 0 : selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2362 : : {
2363 : 0 : struct selector *s = &ctl->selectors[selector_id];
2364 : 0 : struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2365 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2366 : : uint32_t group_id;
2367 : :
2368 : : /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2369 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2370 : 0 : struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2371 : :
2372 [ # # ]: 0 : if (gp) {
2373 : 0 : ts_next->obj = ts->obj;
2374 : 0 : break;
2375 : : }
2376 : : }
2377 : 0 : }
2378 : :
2379 : : static void
2380 : 0 : selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2381 : : {
2382 : 0 : struct selector *s = &ctl->selectors[selector_id];
2383 : : uint32_t group_id;
2384 : :
2385 : : /* Discard any pending group member changes (s->pending_groups[group_id]). */
2386 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2387 : 0 : selector_pending_group_members_free(s, group_id);
2388 : :
2389 : : /* Discard any pending group deletions. */
2390 : 0 : memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2391 : 0 : }
2392 : :
2393 : : static struct rte_swx_table_entry *
2394 : 0 : learner_default_entry_alloc(struct learner *l)
2395 : : {
2396 : : struct rte_swx_table_entry *entry;
2397 : :
2398 : 0 : entry = calloc(1, sizeof(struct rte_swx_table_entry));
2399 [ # # ]: 0 : if (!entry)
2400 : 0 : goto error;
2401 : :
2402 : : /* action_data. */
2403 [ # # ]: 0 : if (l->action_data_size) {
2404 : 0 : entry->action_data = calloc(1, l->action_data_size);
2405 [ # # ]: 0 : if (!entry->action_data)
2406 : 0 : goto error;
2407 : : }
2408 : :
2409 : : return entry;
2410 : :
2411 : 0 : error:
2412 : 0 : table_entry_free(entry);
2413 : 0 : return NULL;
2414 : : }
2415 : :
2416 : : static int
2417 : 0 : learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2418 : : uint32_t learner_id,
2419 : : struct rte_swx_table_entry *entry)
2420 : : {
2421 : 0 : struct learner *l = &ctl->learners[learner_id];
2422 : : struct action *a;
2423 : : uint32_t i;
2424 : :
2425 [ # # ]: 0 : CHECK(entry, EINVAL);
2426 : :
2427 : : /* action_id. */
2428 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++)
2429 [ # # ]: 0 : if (entry->action_id == l->actions[i].action_id)
2430 : : break;
2431 : :
2432 [ # # ]: 0 : CHECK(i < l->info.n_actions, EINVAL);
2433 : :
2434 : : /* action_data. */
2435 : 0 : a = &ctl->actions[entry->action_id];
2436 [ # # # # ]: 0 : CHECK(!(a->data_size && !entry->action_data), EINVAL);
2437 : :
2438 : : return 0;
2439 : : }
2440 : :
2441 : : static struct rte_swx_table_entry *
2442 : 0 : learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2443 : : uint32_t learner_id,
2444 : : struct rte_swx_table_entry *entry)
2445 : : {
2446 : 0 : struct learner *l = &ctl->learners[learner_id];
2447 : : struct rte_swx_table_entry *new_entry = NULL;
2448 : : struct action *a;
2449 : : uint32_t i;
2450 : :
2451 [ # # ]: 0 : if (!entry)
2452 : 0 : goto error;
2453 : :
2454 : 0 : new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2455 [ # # ]: 0 : if (!new_entry)
2456 : 0 : goto error;
2457 : :
2458 : : /* action_id. */
2459 [ # # ]: 0 : for (i = 0; i < l->info.n_actions; i++)
2460 [ # # ]: 0 : if (entry->action_id == l->actions[i].action_id)
2461 : : break;
2462 : :
2463 [ # # ]: 0 : if (i >= l->info.n_actions)
2464 : 0 : goto error;
2465 : :
2466 : 0 : new_entry->action_id = entry->action_id;
2467 : :
2468 : : /* action_data. */
2469 : 0 : a = &ctl->actions[entry->action_id];
2470 [ # # # # ]: 0 : if (a->data_size && !entry->action_data)
2471 : 0 : goto error;
2472 : :
2473 : : /* The table layer provisions a constant action data size per
2474 : : * entry, which should be the largest data size for all the
2475 : : * actions enabled for the current table, and attempts to copy
2476 : : * this many bytes each time a table entry is added, even if the
2477 : : * specific action requires less data or even no data at all,
2478 : : * hence we always have to allocate the max.
2479 : : */
2480 : 0 : new_entry->action_data = calloc(1, l->action_data_size);
2481 [ # # ]: 0 : if (!new_entry->action_data)
2482 : 0 : goto error;
2483 : :
2484 [ # # ]: 0 : if (a->data_size)
2485 : 0 : memcpy(new_entry->action_data, entry->action_data, a->data_size);
2486 : :
2487 : : return new_entry;
2488 : :
2489 : 0 : error:
2490 : 0 : table_entry_free(new_entry);
2491 : 0 : return NULL;
2492 : : }
2493 : :
2494 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_learner_default_entry_add, 21.11)
2495 : : int
2496 : 0 : rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2497 : : const char *learner_name,
2498 : : struct rte_swx_table_entry *entry)
2499 : : {
2500 : : struct learner *l;
2501 : : struct rte_swx_table_entry *new_entry;
2502 : : uint32_t learner_id;
2503 : :
2504 [ # # ]: 0 : CHECK(ctl, EINVAL);
2505 : :
2506 [ # # # # ]: 0 : CHECK(learner_name && learner_name[0], EINVAL);
2507 : 0 : l = learner_find(ctl, learner_name);
2508 [ # # ]: 0 : CHECK(l, EINVAL);
2509 : 0 : learner_id = l - ctl->learners;
2510 [ # # ]: 0 : CHECK(!l->info.default_action_is_const, EINVAL);
2511 : :
2512 [ # # ]: 0 : CHECK(entry, EINVAL);
2513 [ # # ]: 0 : CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2514 : :
2515 [ # # ]: 0 : CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2516 : :
2517 : 0 : new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2518 [ # # ]: 0 : CHECK(new_entry, ENOMEM);
2519 : :
2520 : 0 : learner_pending_default_free(l);
2521 : :
2522 : 0 : l->pending_default = new_entry;
2523 : 0 : return 0;
2524 : : }
2525 : :
2526 : : static void
2527 : 0 : learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2528 : : {
2529 : 0 : struct learner *l = &ctl->learners[learner_id];
2530 : 0 : struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2531 : 0 : ctl->info.n_selectors + learner_id];
2532 : : struct action *a;
2533 : : uint8_t *action_data;
2534 : : uint64_t action_id;
2535 : :
2536 : : /* Copy the pending default entry. */
2537 [ # # ]: 0 : if (!l->pending_default)
2538 : : return;
2539 : :
2540 : 0 : action_id = l->pending_default->action_id;
2541 : 0 : action_data = l->pending_default->action_data;
2542 : 0 : a = &ctl->actions[action_id];
2543 : :
2544 [ # # ]: 0 : if (a->data_size)
2545 : 0 : memcpy(ts_next->default_action_data, action_data, a->data_size);
2546 : :
2547 : 0 : ts_next->default_action_id = action_id;
2548 : : }
2549 : :
2550 : : static void
2551 : : learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2552 : : {
2553 : 0 : struct learner *l = &ctl->learners[learner_id];
2554 : :
2555 : : /* Free up the pending default entry, as it is now part of the table. */
2556 : 0 : learner_pending_default_free(l);
2557 : : }
2558 : :
2559 : : static void
2560 : : learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2561 : : {
2562 : 0 : struct learner *l = &ctl->learners[learner_id];
2563 : :
2564 : : /* Free up the pending default entry, as it is no longer going to be added to the table. */
2565 : 0 : learner_pending_default_free(l);
2566 : : }
2567 : :
2568 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_commit, 20.11)
2569 : : int
2570 : 0 : rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2571 : : {
2572 : : struct rte_swx_table_state *ts;
2573 : : int status = 0;
2574 : : uint32_t i;
2575 : :
2576 [ # # ]: 0 : CHECK(ctl, EINVAL);
2577 : :
2578 : : /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2579 : : * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2580 : : * We must be able to fully revert all the changes that can fail as if they never happened.
2581 : : */
2582 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2583 : 0 : status = table_rollfwd0(ctl, i, 0);
2584 [ # # ]: 0 : if (status)
2585 : 0 : goto rollback;
2586 : : }
2587 : :
2588 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2589 : 0 : status = selector_rollfwd(ctl, i);
2590 [ # # ]: 0 : if (status)
2591 : 0 : goto rollback;
2592 : : }
2593 : :
2594 : : /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2595 : : * onwards, the transaction is guaranteed to be successful.
2596 : : */
2597 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++)
2598 : 0 : table_rollfwd1(ctl, i);
2599 : :
2600 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2601 : 0 : learner_rollfwd(ctl, i);
2602 : :
2603 : : /* Swap the table state for the data plane. The current ts and ts_next
2604 : : * become the new ts_next and ts, respectively.
2605 : : */
2606 : 0 : rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2607 : 0 : usleep(100);
2608 : 0 : ts = ctl->ts;
2609 : 0 : ctl->ts = ctl->ts_next;
2610 : 0 : ctl->ts_next = ts;
2611 : :
2612 : : /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2613 : : * the current ts_next in sync with the current ts. Since the changes that can fail did
2614 : : * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2615 : : * current ts_next, hence no error checking is needed.
2616 : : */
2617 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2618 : 0 : table_rollfwd0(ctl, i, 1);
2619 : 0 : table_rollfwd1(ctl, i);
2620 : 0 : table_rollfwd2(ctl, i);
2621 : : }
2622 : :
2623 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2624 : 0 : selector_rollfwd(ctl, i);
2625 : 0 : selector_rollfwd_finalize(ctl, i);
2626 : : }
2627 : :
2628 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++) {
2629 : 0 : learner_rollfwd(ctl, i);
2630 : : learner_rollfwd_finalize(ctl, i);
2631 : : }
2632 : :
2633 : : return 0;
2634 : :
2635 : 0 : rollback:
2636 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++) {
2637 : 0 : table_rollback(ctl, i);
2638 [ # # ]: 0 : if (abort_on_fail)
2639 : 0 : table_abort(ctl, i);
2640 : : }
2641 : :
2642 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++) {
2643 : 0 : selector_rollback(ctl, i);
2644 [ # # ]: 0 : if (abort_on_fail)
2645 : 0 : selector_abort(ctl, i);
2646 : : }
2647 : :
2648 [ # # ]: 0 : if (abort_on_fail)
2649 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2650 : : learner_abort(ctl, i);
2651 : :
2652 : : return status;
2653 : : }
2654 : :
2655 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_abort, 20.11)
2656 : : void
2657 : 0 : rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2658 : : {
2659 : : uint32_t i;
2660 : :
2661 [ # # ]: 0 : if (!ctl)
2662 : : return;
2663 : :
2664 [ # # ]: 0 : for (i = 0; i < ctl->info.n_tables; i++)
2665 : 0 : table_abort(ctl, i);
2666 : :
2667 [ # # ]: 0 : for (i = 0; i < ctl->info.n_selectors; i++)
2668 : 0 : selector_abort(ctl, i);
2669 : :
2670 [ # # ]: 0 : for (i = 0; i < ctl->info.n_learners; i++)
2671 : : learner_abort(ctl, i);
2672 : : }
2673 : :
2674 : : static int
2675 : 0 : mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2676 : : {
2677 : : uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2678 : :
2679 [ # # ]: 0 : if (!mask) {
2680 : 0 : *prefix_length = 0;
2681 : 0 : return 0;
2682 : : }
2683 : :
2684 : : /* Count trailing zero bits. */
2685 [ # # ]: 0 : for (i = 0; i < 64; i++) {
2686 [ # # ]: 0 : if (mask & (1LLU << i))
2687 : : break;
2688 : :
2689 : 0 : n_trailing_zeros++;
2690 : : }
2691 : :
2692 : : /* Count the one bits that follow. */
2693 [ # # ]: 0 : for ( ; i < 64; i++) {
2694 [ # # ]: 0 : if (!(mask & (1LLU << i)))
2695 : : break;
2696 : :
2697 : 0 : n_ones++;
2698 : : }
2699 : :
2700 : : /* Check that no more one bits are present */
2701 [ # # ]: 0 : for ( ; i < 64; i++)
2702 [ # # ]: 0 : if (mask & (1LLU << i))
2703 : : return -EINVAL;
2704 : :
2705 : : /* Check that the input mask is a prefix or the right length. */
2706 [ # # ]: 0 : if (n_ones + n_trailing_zeros != mask_length)
2707 : : return -EINVAL;
2708 : :
2709 : 0 : *prefix_length = n_ones;
2710 : 0 : return 0;
2711 : : }
2712 : :
2713 : : static int
2714 : 0 : large_mask_to_prefix(uint8_t *mask, uint32_t n_mask_bytes, uint32_t *prefix_length)
2715 : : {
2716 : : uint32_t pl, i;
2717 : :
2718 : : /* Check input arguments. */
2719 [ # # # # ]: 0 : if (!mask || !n_mask_bytes || !prefix_length)
2720 : : return -EINVAL;
2721 : :
2722 : : /* Count leading bits of one. */
2723 [ # # ]: 0 : for (i = 0; i < n_mask_bytes * 8; i++) {
2724 : 0 : uint32_t byte_id = i / 8;
2725 : : uint32_t bit_id = i & 7;
2726 : :
2727 : 0 : uint32_t byte = mask[byte_id];
2728 : 0 : uint32_t bit = byte & (1 << (7 - bit_id));
2729 : :
2730 [ # # ]: 0 : if (!bit)
2731 : : break;
2732 : : }
2733 : :
2734 : : /* Save the potential prefix length. */
2735 : : pl = i;
2736 : :
2737 : : /* Check that all remaining bits are zeros. */
2738 [ # # ]: 0 : for ( ; i < n_mask_bytes * 8; i++) {
2739 : 0 : uint32_t byte_id = i / 8;
2740 : : uint32_t bit_id = i & 7;
2741 : :
2742 : 0 : uint32_t byte = mask[byte_id];
2743 : 0 : uint32_t bit = byte & (1 << (7 - bit_id));
2744 : :
2745 [ # # ]: 0 : if (bit)
2746 : : break;
2747 : : }
2748 : :
2749 [ # # ]: 0 : if (i < n_mask_bytes * 8)
2750 : : return -EINVAL;
2751 : :
2752 : 0 : *prefix_length = pl;
2753 : 0 : return 0;
2754 : : }
2755 : :
2756 : : static int
2757 : : char_to_hex(char c, uint8_t *val)
2758 : : {
2759 : 0 : if (c >= '0' && c <= '9') {
2760 : : *val = c - '0';
2761 : : return 0;
2762 : : }
2763 : :
2764 [ # # # # ]: 0 : if (c >= 'A' && c <= 'F') {
2765 : 0 : *val = c - 'A' + 10;
2766 : : return 0;
2767 : : }
2768 : :
2769 [ # # # # ]: 0 : if (c >= 'a' && c <= 'f') {
2770 : 0 : *val = c - 'a' + 10;
2771 : : return 0;
2772 : : }
2773 : :
2774 : : return -EINVAL;
2775 : : }
2776 : :
2777 : : static int
2778 : 0 : hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
2779 : : {
2780 : : uint32_t i;
2781 : :
2782 : : /* Check input arguments. */
2783 [ # # # # : 0 : if (!src || !src[0] || !dst || !n_dst_bytes)
# # ]
2784 : : return -EINVAL;
2785 : :
2786 : : /* Skip any leading "0x" or "0X" in the src string. */
2787 [ # # # # ]: 0 : if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
2788 : 0 : src += 2;
2789 : :
2790 : : /* Convert each group of two hex characters in the src string to one byte in dst array. */
2791 [ # # ]: 0 : for (i = 0; i < n_dst_bytes; i++) {
2792 : : uint8_t a, b;
2793 : : int status;
2794 : :
2795 [ # # ]: 0 : status = char_to_hex(*src, &a);
2796 : : if (status)
2797 : : return status;
2798 : : src++;
2799 : :
2800 [ # # ]: 0 : status = char_to_hex(*src, &b);
2801 : : if (status)
2802 : : return status;
2803 : 0 : src++;
2804 : :
2805 : 0 : dst[i] = a * 16 + b;
2806 : : }
2807 : :
2808 : : /* Check for the end of the src string. */
2809 [ # # ]: 0 : if (*src)
2810 : 0 : return -EINVAL;
2811 : :
2812 : : return 0;
2813 : : }
2814 : :
2815 : : static int
2816 : 0 : table_entry_match_field_read(struct table *table,
2817 : : struct rte_swx_table_entry *entry,
2818 : : uint32_t mf_id,
2819 : : char *mf_val,
2820 : : char *mf_mask,
2821 : : int *lpm,
2822 : : uint32_t *lpm_prefix_length_max,
2823 : : uint32_t *lpm_prefix_length)
2824 : : {
2825 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2826 : 0 : uint64_t val, mask = UINT64_MAX;
2827 : 0 : uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2828 : :
2829 : : /*
2830 : : * Mask.
2831 : : */
2832 [ # # ]: 0 : if (mf_mask) {
2833 : : /* Parse. */
2834 : 0 : mask = strtoull(mf_mask, &mf_mask, 0);
2835 [ # # ]: 0 : if (mf_mask[0])
2836 : : return -EINVAL;
2837 : :
2838 : : /* LPM. */
2839 [ # # ]: 0 : if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2840 : : int status;
2841 : :
2842 : 0 : *lpm = 1;
2843 : :
2844 : 0 : *lpm_prefix_length_max = mf->n_bits;
2845 : :
2846 : 0 : status = mask_to_prefix(mask, mf->n_bits, lpm_prefix_length);
2847 [ # # ]: 0 : if (status)
2848 : : return status;
2849 : : }
2850 : :
2851 : : /* Endianness conversion. */
2852 [ # # ]: 0 : if (mf->is_header)
2853 [ # # ]: 0 : mask = field_hton(mask, mf->n_bits);
2854 : : }
2855 : :
2856 : : /* Copy to entry. */
2857 [ # # ]: 0 : if (entry->key_mask)
2858 : 0 : memcpy(&entry->key_mask[offset], (uint8_t *)&mask, mf->n_bits / 8);
2859 : :
2860 : : /*
2861 : : * Value.
2862 : : */
2863 : : /* Parse. */
2864 : 0 : val = strtoull(mf_val, &mf_val, 0);
2865 [ # # ]: 0 : if (mf_val[0])
2866 : : return -EINVAL;
2867 : :
2868 : : /* Endianness conversion. */
2869 [ # # ]: 0 : if (mf->is_header)
2870 [ # # ]: 0 : val = field_hton(val, mf->n_bits);
2871 : :
2872 : : /* Copy to entry. */
2873 : 0 : memcpy(&entry->key[offset], (uint8_t *)&val, mf->n_bits / 8);
2874 : :
2875 : 0 : return 0;
2876 : : }
2877 : :
2878 : : static int
2879 : 0 : table_entry_action_argument_read(struct action *action,
2880 : : struct rte_swx_table_entry *entry,
2881 : : uint32_t arg_id,
2882 : : uint32_t arg_offset,
2883 : : char *arg_val)
2884 : : {
2885 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2886 : : uint64_t val;
2887 : :
2888 : 0 : val = strtoull(arg_val, &arg_val, 0);
2889 [ # # ]: 0 : if (arg_val[0])
2890 : : return -EINVAL;
2891 : :
2892 : : /* Endianness conversion. */
2893 [ # # ]: 0 : if (arg->is_network_byte_order)
2894 [ # # ]: 0 : val = field_hton(val, arg->n_bits);
2895 : :
2896 : : /* Copy to entry. */
2897 : 0 : memcpy(&entry->action_data[arg_offset],
2898 : : (uint8_t *)&val,
2899 : 0 : arg->n_bits / 8);
2900 : :
2901 : 0 : return 0;
2902 : : }
2903 : :
2904 : : static int
2905 : 0 : table_entry_large_match_field_read(struct table *table,
2906 : : struct rte_swx_table_entry *entry,
2907 : : uint32_t mf_id,
2908 : : char *mf_val,
2909 : : char *mf_mask,
2910 : : int *lpm,
2911 : : uint32_t *lpm_prefix_length_max,
2912 : : uint32_t *lpm_prefix_length)
2913 : : {
2914 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2915 : 0 : uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2916 : : int status;
2917 : :
2918 : : /*
2919 : : * Mask.
2920 : : */
2921 [ # # ]: 0 : if (!entry->key_mask)
2922 : 0 : goto value;
2923 : :
2924 [ # # ]: 0 : if (!mf_mask) {
2925 : : /* Set mask to all-ones. */
2926 : 0 : memset(&entry->key_mask[offset], 0xFF, mf->n_bits / 8);
2927 : 0 : goto value;
2928 : : }
2929 : :
2930 : : /* Parse. */
2931 : 0 : status = hex_string_parse(mf_mask, &entry->key_mask[offset], mf->n_bits / 8);
2932 [ # # ]: 0 : if (status)
2933 : : return -EINVAL;
2934 : :
2935 : : /* LPM. */
2936 [ # # ]: 0 : if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2937 : 0 : *lpm = 1;
2938 : :
2939 : 0 : *lpm_prefix_length_max = mf->n_bits;
2940 : :
2941 : 0 : status = large_mask_to_prefix(&entry->key_mask[offset],
2942 : : mf->n_bits / 8,
2943 : : lpm_prefix_length);
2944 [ # # ]: 0 : if (status)
2945 : : return status;
2946 : : }
2947 : :
2948 : : /*
2949 : : * Value.
2950 : : */
2951 : 0 : value:
2952 : : /* Parse. */
2953 : 0 : status = hex_string_parse(mf_val, &entry->key[offset], mf->n_bits / 8);
2954 [ # # ]: 0 : if (status)
2955 : 0 : return -EINVAL;
2956 : :
2957 : : return 0;
2958 : : }
2959 : :
2960 : : static int
2961 : : table_entry_large_action_argument_read(struct action *action,
2962 : : struct rte_swx_table_entry *entry,
2963 : : uint32_t arg_id,
2964 : : uint32_t arg_offset,
2965 : : char *arg_val)
2966 : : {
2967 : : struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2968 : : int status;
2969 : :
2970 : 0 : status = hex_string_parse(arg_val, &entry->action_data[arg_offset], arg->n_bits / 8);
2971 [ # # ]: 0 : if (status)
2972 : : return -EINVAL;
2973 : :
2974 : : return 0;
2975 : : }
2976 : :
2977 : : static int
2978 : : token_is_comment(const char *token)
2979 : : {
2980 [ # # # # ]: 0 : if ((token[0] == '#') ||
2981 [ # # # # ]: 0 : (token[0] == ';') ||
2982 [ # # # # ]: 0 : ((token[0] == '/') && (token[1] == '/')))
2983 : : return 1; /* TRUE. */
2984 : :
2985 : : return 0; /* FALSE. */
2986 : : }
2987 : :
2988 : : #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2989 : :
2990 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_entry_read, 20.11)
2991 : : struct rte_swx_table_entry *
2992 : 0 : rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2993 : : const char *table_name,
2994 : : const char *string,
2995 : : int *is_blank_or_comment)
2996 : : {
2997 : : char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2998 : : struct table *table;
2999 : : struct action *action;
3000 : : struct rte_swx_table_entry *entry = NULL;
3001 : : char *s0 = NULL, *s;
3002 : 0 : uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
3003 : 0 : int lpm = 0, blank_or_comment = 0;
3004 : :
3005 : : /* Check input arguments. */
3006 [ # # ]: 0 : if (!ctl)
3007 : 0 : goto error;
3008 : :
3009 [ # # # # ]: 0 : if (!table_name || !table_name[0])
3010 : 0 : goto error;
3011 : :
3012 : 0 : table = table_find(ctl, table_name);
3013 [ # # ]: 0 : if (!table)
3014 : 0 : goto error;
3015 : :
3016 [ # # # # ]: 0 : if (!string || !string[0])
3017 : 0 : goto error;
3018 : :
3019 : : /* Memory allocation. */
3020 : 0 : s0 = strdup(string);
3021 [ # # ]: 0 : if (!s0)
3022 : 0 : goto error;
3023 : :
3024 : 0 : entry = table_entry_alloc(table);
3025 [ # # ]: 0 : if (!entry)
3026 : 0 : goto error;
3027 : :
3028 : : /* Parse the string into tokens. */
3029 : 0 : for (s = s0; ; ) {
3030 : : char *token;
3031 : :
3032 : 0 : token = strtok_r(s, " \f\n\r\t\v", &s);
3033 [ # # ]: 0 : if (!token || token_is_comment(token))
3034 : : break;
3035 : :
3036 [ # # ]: 0 : if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3037 : 0 : goto error;
3038 : :
3039 : 0 : token_array[n_tokens] = token;
3040 : 0 : n_tokens++;
3041 : : }
3042 : :
3043 [ # # ]: 0 : if (!n_tokens) {
3044 : : blank_or_comment = 1;
3045 : 0 : goto error;
3046 : : }
3047 : :
3048 : : tokens = token_array;
3049 : :
3050 : : /*
3051 : : * Match.
3052 : : */
3053 [ # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "match")))
3054 : 0 : goto action;
3055 : :
3056 [ # # ]: 0 : if (n_tokens < 1 + table->info.n_match_fields)
3057 : 0 : goto error;
3058 : :
3059 [ # # ]: 0 : for (i = 0; i < table->info.n_match_fields; i++) {
3060 : 0 : struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
3061 : 0 : char *mf_val = tokens[1 + i], *mf_mask = NULL;
3062 : : int status;
3063 : :
3064 : 0 : mf_mask = strchr(mf_val, '/');
3065 [ # # ]: 0 : if (mf_mask) {
3066 : 0 : *mf_mask = 0;
3067 : 0 : mf_mask++;
3068 : : }
3069 : :
3070 [ # # ]: 0 : if (mf->n_bits <= 64)
3071 : 0 : status = table_entry_match_field_read(table,
3072 : : entry,
3073 : : i,
3074 : : mf_val,
3075 : : mf_mask,
3076 : : &lpm,
3077 : : &lpm_prefix_length_max,
3078 : : &lpm_prefix_length);
3079 : : else
3080 : 0 : status = table_entry_large_match_field_read(table,
3081 : : entry,
3082 : : i,
3083 : : mf_val,
3084 : : mf_mask,
3085 : : &lpm,
3086 : : &lpm_prefix_length_max,
3087 : : &lpm_prefix_length);
3088 [ # # ]: 0 : if (status)
3089 : 0 : goto error;
3090 : :
3091 : : }
3092 : :
3093 : 0 : tokens += 1 + table->info.n_match_fields;
3094 : 0 : n_tokens -= 1 + table->info.n_match_fields;
3095 : :
3096 : : /*
3097 : : * Match priority.
3098 : : */
3099 [ # # # # ]: 0 : if (n_tokens && !strcmp(tokens[0], "priority")) {
3100 : 0 : char *priority = tokens[1];
3101 : : uint32_t val;
3102 : :
3103 [ # # ]: 0 : if (n_tokens < 2)
3104 : 0 : goto error;
3105 : :
3106 : : /* Parse. */
3107 : 0 : val = strtoul(priority, &priority, 0);
3108 [ # # ]: 0 : if (priority[0])
3109 : 0 : goto error;
3110 : :
3111 : : /* Copy to entry. */
3112 : 0 : entry->key_priority = val;
3113 : :
3114 : 0 : tokens += 2;
3115 : 0 : n_tokens -= 2;
3116 : : }
3117 : :
3118 : : /* LPM. */
3119 [ # # ]: 0 : if (lpm)
3120 : 0 : entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
3121 : :
3122 : : /*
3123 : : * Action.
3124 : : */
3125 : 0 : action:
3126 [ # # # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "action")))
3127 : 0 : goto other;
3128 : :
3129 [ # # ]: 0 : if (n_tokens < 2)
3130 : 0 : goto error;
3131 : :
3132 : 0 : action = action_find(ctl, tokens[1]);
3133 [ # # ]: 0 : if (!action)
3134 : 0 : goto error;
3135 : :
3136 [ # # ]: 0 : if (n_tokens < 2 + action->info.n_args * 2)
3137 : 0 : goto error;
3138 : :
3139 : : /* action_id. */
3140 : 0 : entry->action_id = action - ctl->actions;
3141 : :
3142 : : /* action_data. */
3143 [ # # ]: 0 : for (i = 0; i < action->info.n_args; i++) {
3144 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3145 : : char *arg_name, *arg_val;
3146 : : int status;
3147 : :
3148 : 0 : arg_name = tokens[2 + i * 2];
3149 : 0 : arg_val = tokens[2 + i * 2 + 1];
3150 : :
3151 [ # # ]: 0 : if (strcmp(arg_name, arg->name))
3152 : 0 : goto error;
3153 : :
3154 [ # # ]: 0 : if (arg->n_bits <= 64)
3155 : 0 : status = table_entry_action_argument_read(action,
3156 : : entry,
3157 : : i,
3158 : : arg_offset,
3159 : : arg_val);
3160 : : else
3161 : : status = table_entry_large_action_argument_read(action,
3162 : : entry,
3163 : : i,
3164 : : arg_offset,
3165 : : arg_val);
3166 [ # # ]: 0 : if (status)
3167 : 0 : goto error;
3168 : :
3169 : 0 : arg_offset += arg->n_bits / 8;
3170 : : }
3171 : :
3172 : 0 : tokens += 2 + action->info.n_args * 2;
3173 : 0 : n_tokens -= 2 + action->info.n_args * 2;
3174 : :
3175 : 0 : other:
3176 [ # # ]: 0 : if (n_tokens)
3177 : 0 : goto error;
3178 : :
3179 : 0 : free(s0);
3180 : 0 : return entry;
3181 : :
3182 : 0 : error:
3183 : 0 : table_entry_free(entry);
3184 : 0 : free(s0);
3185 [ # # ]: 0 : if (is_blank_or_comment)
3186 : 0 : *is_blank_or_comment = blank_or_comment;
3187 : : return NULL;
3188 : : }
3189 : :
3190 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_learner_default_entry_read, 21.11)
3191 : : struct rte_swx_table_entry *
3192 : 0 : rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
3193 : : const char *learner_name,
3194 : : const char *string,
3195 : : int *is_blank_or_comment)
3196 : : {
3197 : : char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
3198 : : struct learner *l;
3199 : : struct action *action;
3200 : : struct rte_swx_table_entry *entry = NULL;
3201 : : char *s0 = NULL, *s;
3202 : : uint32_t n_tokens = 0, arg_offset = 0, i;
3203 : : int blank_or_comment = 0;
3204 : :
3205 : : /* Check input arguments. */
3206 [ # # ]: 0 : if (!ctl)
3207 : 0 : goto error;
3208 : :
3209 [ # # # # ]: 0 : if (!learner_name || !learner_name[0])
3210 : 0 : goto error;
3211 : :
3212 : 0 : l = learner_find(ctl, learner_name);
3213 [ # # ]: 0 : if (!l)
3214 : 0 : goto error;
3215 : :
3216 [ # # # # ]: 0 : if (!string || !string[0])
3217 : 0 : goto error;
3218 : :
3219 : : /* Memory allocation. */
3220 : 0 : s0 = strdup(string);
3221 [ # # ]: 0 : if (!s0)
3222 : 0 : goto error;
3223 : :
3224 : 0 : entry = learner_default_entry_alloc(l);
3225 [ # # ]: 0 : if (!entry)
3226 : 0 : goto error;
3227 : :
3228 : : /* Parse the string into tokens. */
3229 : 0 : for (s = s0; ; ) {
3230 : : char *token;
3231 : :
3232 : 0 : token = strtok_r(s, " \f\n\r\t\v", &s);
3233 [ # # ]: 0 : if (!token || token_is_comment(token))
3234 : : break;
3235 : :
3236 [ # # ]: 0 : if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3237 : 0 : goto error;
3238 : :
3239 : 0 : token_array[n_tokens] = token;
3240 : 0 : n_tokens++;
3241 : : }
3242 : :
3243 [ # # ]: 0 : if (!n_tokens) {
3244 : : blank_or_comment = 1;
3245 : 0 : goto error;
3246 : : }
3247 : :
3248 : : tokens = token_array;
3249 : :
3250 : : /*
3251 : : * Action.
3252 : : */
3253 [ # # ]: 0 : if (!(n_tokens && !strcmp(tokens[0], "action")))
3254 : 0 : goto other;
3255 : :
3256 [ # # ]: 0 : if (n_tokens < 2)
3257 : 0 : goto error;
3258 : :
3259 : 0 : action = action_find(ctl, tokens[1]);
3260 [ # # ]: 0 : if (!action)
3261 : 0 : goto error;
3262 : :
3263 [ # # ]: 0 : if (n_tokens < 2 + action->info.n_args * 2)
3264 : 0 : goto error;
3265 : :
3266 : : /* action_id. */
3267 : 0 : entry->action_id = action - ctl->actions;
3268 : :
3269 : : /* action_data. */
3270 [ # # ]: 0 : for (i = 0; i < action->info.n_args; i++) {
3271 : 0 : struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3272 : : char *arg_name, *arg_val;
3273 : : uint64_t val;
3274 : :
3275 : 0 : arg_name = tokens[2 + i * 2];
3276 : 0 : arg_val = tokens[2 + i * 2 + 1];
3277 : :
3278 [ # # ]: 0 : if (strcmp(arg_name, arg->name))
3279 : 0 : goto error;
3280 : :
3281 : 0 : val = strtoull(arg_val, &arg_val, 0);
3282 [ # # ]: 0 : if (arg_val[0])
3283 : 0 : goto error;
3284 : :
3285 : : /* Endianness conversion. */
3286 [ # # ]: 0 : if (arg->is_network_byte_order)
3287 [ # # ]: 0 : val = field_hton(val, arg->n_bits);
3288 : :
3289 : : /* Copy to entry. */
3290 : 0 : memcpy(&entry->action_data[arg_offset],
3291 : : (uint8_t *)&val,
3292 : 0 : arg->n_bits / 8);
3293 : :
3294 : 0 : arg_offset += arg->n_bits / 8;
3295 : : }
3296 : :
3297 : 0 : tokens += 2 + action->info.n_args * 2;
3298 : 0 : n_tokens -= 2 + action->info.n_args * 2;
3299 : :
3300 : 0 : other:
3301 [ # # ]: 0 : if (n_tokens)
3302 : 0 : goto error;
3303 : :
3304 : 0 : free(s0);
3305 : 0 : return entry;
3306 : :
3307 : 0 : error:
3308 : 0 : table_entry_free(entry);
3309 : 0 : free(s0);
3310 [ # # ]: 0 : if (is_blank_or_comment)
3311 : 0 : *is_blank_or_comment = blank_or_comment;
3312 : : return NULL;
3313 : : }
3314 : :
3315 : : static void
3316 : 0 : table_entry_printf(FILE *f,
3317 : : struct rte_swx_ctl_pipeline *ctl,
3318 : : struct table *table,
3319 : : struct rte_swx_table_entry *entry)
3320 : : {
3321 : 0 : struct action *action = &ctl->actions[entry->action_id];
3322 : : uint32_t i;
3323 : :
3324 : : fprintf(f, "match ");
3325 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3326 : 0 : fprintf(f, "%02x", entry->key[i]);
3327 : :
3328 [ # # ]: 0 : if (entry->key_mask) {
3329 : : fprintf(f, "/");
3330 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3331 : 0 : fprintf(f, "%02x", entry->key_mask[i]);
3332 : : }
3333 : :
3334 : 0 : fprintf(f, " priority %u", entry->key_priority);
3335 : :
3336 : 0 : fprintf(f, " action %s ", action->info.name);
3337 [ # # ]: 0 : for (i = 0; i < action->data_size; i++)
3338 : 0 : fprintf(f, "%02x", entry->action_data[i]);
3339 : :
3340 : : fprintf(f, "\n");
3341 : 0 : }
3342 : :
3343 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_table_fprintf, 20.11)
3344 : : int
3345 : 0 : rte_swx_ctl_pipeline_table_fprintf(FILE *f,
3346 : : struct rte_swx_ctl_pipeline *ctl,
3347 : : const char *table_name)
3348 : : {
3349 : : struct table *table;
3350 : : struct rte_swx_table_entry *entry;
3351 : : uint32_t n_entries = 0, i;
3352 : :
3353 [ # # # # : 0 : if (!f || !ctl || !table_name || !table_name[0])
# # ]
3354 : : return -EINVAL;
3355 : :
3356 : 0 : table = table_find(ctl, table_name);
3357 [ # # ]: 0 : if (!table)
3358 : : return -EINVAL;
3359 : :
3360 : : /* Table. */
3361 : 0 : fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3362 : 0 : table->info.name,
3363 : : table->params.key_size,
3364 : : table->params.key_offset);
3365 : :
3366 [ # # ]: 0 : for (i = 0; i < table->params.key_size; i++)
3367 : 0 : fprintf(f, "%02x", table->params.key_mask0[i]);
3368 : :
3369 : 0 : fprintf(f, "], action data size %u bytes\n",
3370 : : table->params.action_data_size);
3371 : :
3372 : : /* Table entries. */
3373 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->entries, node) {
3374 : 0 : table_entry_printf(f, ctl, table, entry);
3375 : 0 : n_entries++;
3376 : : }
3377 : :
3378 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3379 : 0 : table_entry_printf(f, ctl, table, entry);
3380 : 0 : n_entries++;
3381 : : }
3382 : :
3383 [ # # ]: 0 : TAILQ_FOREACH(entry, &table->pending_delete, node) {
3384 : 0 : table_entry_printf(f, ctl, table, entry);
3385 : 0 : n_entries++;
3386 : : }
3387 : :
3388 : : fprintf(f, "# Table %s currently has %u entries.\n",
3389 : : table_name,
3390 : : n_entries);
3391 : 0 : return 0;
3392 : : }
3393 : :
3394 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_swx_ctl_pipeline_selector_fprintf, 21.08)
3395 : : int
3396 : 0 : rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3397 : : struct rte_swx_ctl_pipeline *ctl,
3398 : : const char *selector_name)
3399 : : {
3400 : : struct selector *s;
3401 : : uint32_t group_id;
3402 : :
3403 [ # # # # : 0 : if (!f || !ctl || !selector_name || !selector_name[0])
# # ]
3404 : : return -EINVAL;
3405 : :
3406 : 0 : s = selector_find(ctl, selector_name);
3407 [ # # ]: 0 : if (!s)
3408 : : return -EINVAL;
3409 : :
3410 : : /* Selector. */
3411 : 0 : fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3412 : 0 : s->info.name,
3413 : : s->info.n_groups_max,
3414 : : s->info.n_members_per_group_max);
3415 : :
3416 : : /* Groups. */
3417 [ # # ]: 0 : for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3418 : 0 : struct rte_swx_table_selector_group *group = s->groups[group_id];
3419 : : struct rte_swx_table_selector_member *m;
3420 : : uint32_t n_members = 0;
3421 : :
3422 : : fprintf(f, "Group %u = [", group_id);
3423 : :
3424 : : /* Non-empty group. */
3425 [ # # ]: 0 : if (group)
3426 [ # # ]: 0 : TAILQ_FOREACH(m, &group->members, node) {
3427 : 0 : fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3428 : 0 : n_members++;
3429 : : }
3430 : :
3431 : : /* Empty group. */
3432 [ # # ]: 0 : if (!n_members)
3433 : : fprintf(f, "0:1 ");
3434 : :
3435 : : fprintf(f, "]\n");
3436 : : }
3437 : :
3438 : : return 0;
3439 : : }
|