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