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