xref: /dpdk/lib/pipeline/rte_swx_ctl.c (revision 8f393c4ffdc1ff9b46702708781723ca0f17f5ac)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/queue.h>
8 #include <unistd.h>
9 
10 #include <rte_common.h>
11 #include <rte_byteorder.h>
12 
13 #include <rte_swx_table_selector.h>
14 
15 #include "rte_swx_ctl.h"
16 
17 #define CHECK(condition, err_code)                                             \
18 do {                                                                           \
19 	if (!(condition))                                                      \
20 		return -(err_code);                                            \
21 } while (0)
22 
23 #define ntoh64(x) rte_be_to_cpu_64(x)
24 #define hton64(x) rte_cpu_to_be_64(x)
25 
26 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
27 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
28 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
29 #else
30 #define field_ntoh(val, n_bits) (val)
31 #define field_hton(val, n_bits) (val)
32 #endif
33 
34 struct action {
35 	struct rte_swx_ctl_action_info info;
36 	struct rte_swx_ctl_action_arg_info *args;
37 	uint32_t data_size;
38 };
39 
40 struct table {
41 	struct rte_swx_ctl_table_info info;
42 	struct rte_swx_ctl_table_match_field_info *mf;
43 
44 	/* Match field with the smallest offset. */
45 	struct rte_swx_ctl_table_match_field_info *mf_first;
46 
47 	/* Match field with the biggest offset. */
48 	struct rte_swx_ctl_table_match_field_info *mf_last;
49 
50 	struct rte_swx_ctl_table_action_info *actions;
51 	struct rte_swx_table_ops ops;
52 	struct rte_swx_table_params params;
53 
54 	/* Set of "stable" keys: these keys are currently part of the table;
55 	 * these keys will be preserved with no action data changes after the
56 	 * next commit.
57 	 */
58 	struct rte_swx_table_entry_list entries;
59 
60 	/* Set of new keys: these keys are currently NOT part of the table;
61 	 * these keys will be added to the table on the next commit, if
62 	 * the commit operation is successful.
63 	 */
64 	struct rte_swx_table_entry_list pending_add;
65 
66 	/* Set of keys to be modified: these keys are currently part of the
67 	 * table; these keys are still going to be part of the table after the
68 	 * next commit, but their action data will be modified if the commit
69 	 * operation is successful. The modify0 list contains the keys with the
70 	 * current action data, the modify1 list contains the keys with the
71 	 * modified action data.
72 	 */
73 	struct rte_swx_table_entry_list pending_modify0;
74 	struct rte_swx_table_entry_list pending_modify1;
75 
76 	/* Set of keys to be deleted: these keys are currently part of the
77 	 * table; these keys are to be deleted from the table on the next
78 	 * commit, if the commit operation is successful.
79 	 */
80 	struct rte_swx_table_entry_list pending_delete;
81 
82 	/* The pending default action: this is NOT the current default action;
83 	 * this will be the new default action after the next commit, if the
84 	 * next commit operation is successful.
85 	 */
86 	struct rte_swx_table_entry *pending_default;
87 
88 	int is_stub;
89 	uint32_t n_add;
90 	uint32_t n_modify;
91 	uint32_t n_delete;
92 };
93 
94 struct selector {
95 	/* Selector table info. */
96 	struct rte_swx_ctl_selector_info info;
97 
98 	/* group_id field. */
99 	struct rte_swx_ctl_table_match_field_info group_id_field;
100 
101 	/* selector fields. */
102 	struct rte_swx_ctl_table_match_field_info *selector_fields;
103 
104 	/* member_id field. */
105 	struct rte_swx_ctl_table_match_field_info member_id_field;
106 
107 	/* Current selector table. Array of info.n_groups_max elements.*/
108 	struct rte_swx_table_selector_group **groups;
109 
110 	/* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
111 	 */
112 	struct rte_swx_table_selector_group **pending_groups;
113 
114 	/* Valid flag per group. Array of n_groups_max elements. */
115 	int *groups_added;
116 
117 	/* Pending delete flag per group. Group deletion is subject to the next commit. Array of
118 	 * info.n_groups_max elements.
119 	 */
120 	int *groups_pending_delete;
121 
122 	/* Params. */
123 	struct rte_swx_table_selector_params params;
124 };
125 
126 struct rte_swx_ctl_pipeline {
127 	struct rte_swx_ctl_pipeline_info info;
128 	struct rte_swx_pipeline *p;
129 	struct action *actions;
130 	struct table *tables;
131 	struct selector *selectors;
132 	struct rte_swx_table_state *ts;
133 	struct rte_swx_table_state *ts_next;
134 	int numa_node;
135 };
136 
137 static struct action *
138 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
139 {
140 	uint32_t i;
141 
142 	for (i = 0; i < ctl->info.n_actions; i++) {
143 		struct action *a = &ctl->actions[i];
144 
145 		if (!strcmp(action_name, a->info.name))
146 			return a;
147 	}
148 
149 	return NULL;
150 }
151 
152 static void
153 action_free(struct rte_swx_ctl_pipeline *ctl)
154 {
155 	uint32_t i;
156 
157 	if (!ctl->actions)
158 		return;
159 
160 	for (i = 0; i < ctl->info.n_actions; i++) {
161 		struct action *action = &ctl->actions[i];
162 
163 		free(action->args);
164 	}
165 
166 	free(ctl->actions);
167 	ctl->actions = NULL;
168 }
169 
170 static struct table *
171 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
172 {
173 	uint32_t i;
174 
175 	for (i = 0; i < ctl->info.n_tables; i++) {
176 		struct table *table = &ctl->tables[i];
177 
178 		if (!strcmp(table_name, table->info.name))
179 			return table;
180 	}
181 
182 	return NULL;
183 }
184 
185 static int
186 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
187 {
188 	struct table *table = &ctl->tables[table_id];
189 	struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
190 	uint8_t *key_mask = NULL;
191 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
192 	uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
193 
194 	if (table->info.n_match_fields) {
195 		uint32_t n_match_fields_em = 0, i;
196 
197 		/* Find first (smallest offset) and last (biggest offset) match fields. */
198 		first = &table->mf[0];
199 		last = &table->mf[0];
200 
201 		for (i = 1; i < table->info.n_match_fields; i++) {
202 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
203 
204 			if (f->offset < first->offset)
205 				first = f;
206 
207 			if (f->offset > last->offset)
208 				last = f;
209 		}
210 
211 		/* match_type. */
212 		for (i = 0; i < table->info.n_match_fields; i++) {
213 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
214 
215 			if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
216 				n_match_fields_em++;
217 		}
218 
219 		if (n_match_fields_em == table->info.n_match_fields)
220 			match_type = RTE_SWX_TABLE_MATCH_EXACT;
221 
222 		/* key_offset. */
223 		key_offset = first->offset / 8;
224 
225 		/* key_size. */
226 		key_size = (last->offset + last->n_bits - first->offset) / 8;
227 
228 		/* key_mask. */
229 		key_mask = calloc(1, key_size);
230 		CHECK(key_mask, ENOMEM);
231 
232 		for (i = 0; i < table->info.n_match_fields; i++) {
233 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
234 			uint32_t start;
235 			size_t size;
236 
237 			start = (f->offset - first->offset) / 8;
238 			size = f->n_bits / 8;
239 
240 			memset(&key_mask[start], 0xFF, size);
241 		}
242 	}
243 
244 	/* action_data_size. */
245 	for (i = 0; i < table->info.n_actions; i++) {
246 		uint32_t action_id = table->actions[i].action_id;
247 		struct action *a = &ctl->actions[action_id];
248 
249 		if (a->data_size > action_data_size)
250 			action_data_size = a->data_size;
251 	}
252 
253 	/* Fill in. */
254 	table->params.match_type = match_type;
255 	table->params.key_size = key_size;
256 	table->params.key_offset = key_offset;
257 	table->params.key_mask0 = key_mask;
258 	table->params.action_data_size = action_data_size;
259 	table->params.n_keys_max = table->info.size;
260 
261 	table->mf_first = first;
262 	table->mf_last = last;
263 
264 	return 0;
265 }
266 
267 static void
268 table_entry_free(struct rte_swx_table_entry *entry)
269 {
270 	if (!entry)
271 		return;
272 
273 	free(entry->key);
274 	free(entry->key_mask);
275 	free(entry->action_data);
276 	free(entry);
277 }
278 
279 static struct rte_swx_table_entry *
280 table_entry_alloc(struct table *table)
281 {
282 	struct rte_swx_table_entry *entry;
283 
284 	entry = calloc(1, sizeof(struct rte_swx_table_entry));
285 	if (!entry)
286 		goto error;
287 
288 	/* key, key_mask. */
289 	if (!table->is_stub) {
290 		entry->key = calloc(1, table->params.key_size);
291 		if (!entry->key)
292 			goto error;
293 
294 		if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
295 			entry->key_mask = calloc(1, table->params.key_size);
296 			if (!entry->key_mask)
297 				goto error;
298 		}
299 	}
300 
301 	/* action_data. */
302 	if (table->params.action_data_size) {
303 		entry->action_data = calloc(1, table->params.action_data_size);
304 		if (!entry->action_data)
305 			goto error;
306 	}
307 
308 	return entry;
309 
310 error:
311 	table_entry_free(entry);
312 	return NULL;
313 }
314 
315 static int
316 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
317 {
318 	uint8_t *key_mask0 = table->params.key_mask0;
319 	uint32_t key_size = table->params.key_size, i;
320 
321 	if (!entry->key_mask)
322 		return 0;
323 
324 	for (i = 0; i < key_size; i++) {
325 		uint8_t km0 = key_mask0[i];
326 		uint8_t km = entry->key_mask[i];
327 
328 		if ((km & km0) != km0)
329 			return -EINVAL;
330 	}
331 
332 	return 0;
333 }
334 
335 static int
336 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
337 		  uint32_t table_id,
338 		  struct rte_swx_table_entry *entry,
339 		  int key_check,
340 		  int data_check)
341 {
342 	struct table *table = &ctl->tables[table_id];
343 	int status;
344 
345 	CHECK(entry, EINVAL);
346 
347 	if (key_check && !table->is_stub) {
348 		/* key. */
349 		CHECK(entry->key, EINVAL);
350 
351 		/* key_mask. */
352 		if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
353 			status = table_entry_key_check_em(table, entry);
354 			if (status)
355 				return status;
356 		}
357 	}
358 
359 	if (data_check) {
360 		struct action *a;
361 		uint32_t i;
362 
363 		/* action_id. */
364 		for (i = 0; i < table->info.n_actions; i++)
365 			if (entry->action_id == table->actions[i].action_id)
366 				break;
367 
368 		CHECK(i < table->info.n_actions, EINVAL);
369 
370 		/* action_data. */
371 		a = &ctl->actions[entry->action_id];
372 		CHECK(!(a->data_size && !entry->action_data), EINVAL);
373 	}
374 
375 	return 0;
376 }
377 
378 static struct rte_swx_table_entry *
379 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
380 		      uint32_t table_id,
381 		      struct rte_swx_table_entry *entry,
382 		      int key_duplicate,
383 		      int data_duplicate)
384 {
385 	struct table *table = &ctl->tables[table_id];
386 	struct rte_swx_table_entry *new_entry = NULL;
387 
388 	if (!entry)
389 		goto error;
390 
391 	new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
392 	if (!new_entry)
393 		goto error;
394 
395 	if (key_duplicate && !table->is_stub) {
396 		/* key. */
397 		if (!entry->key)
398 			goto error;
399 
400 		new_entry->key = malloc(table->params.key_size);
401 		if (!new_entry->key)
402 			goto error;
403 
404 		memcpy(new_entry->key, entry->key, table->params.key_size);
405 
406 		/* key_signature. */
407 		new_entry->key_signature = entry->key_signature;
408 
409 		/* key_mask. */
410 		if (entry->key_mask) {
411 			new_entry->key_mask = malloc(table->params.key_size);
412 			if (!new_entry->key_mask)
413 				goto error;
414 
415 			memcpy(new_entry->key_mask,
416 			       entry->key_mask,
417 			       table->params.key_size);
418 		}
419 
420 		/* key_priority. */
421 		new_entry->key_priority = entry->key_priority;
422 	}
423 
424 	if (data_duplicate) {
425 		struct action *a;
426 		uint32_t i;
427 
428 		/* action_id. */
429 		for (i = 0; i < table->info.n_actions; i++)
430 			if (entry->action_id == table->actions[i].action_id)
431 				break;
432 
433 		if (i >= table->info.n_actions)
434 			goto error;
435 
436 		new_entry->action_id = entry->action_id;
437 
438 		/* action_data. */
439 		a = &ctl->actions[entry->action_id];
440 		if (a->data_size && !entry->action_data)
441 			goto error;
442 
443 		/* The table layer provisions a constant action data size per
444 		 * entry, which should be the largest data size for all the
445 		 * actions enabled for the current table, and attempts to copy
446 		 * this many bytes each time a table entry is added, even if the
447 		 * specific action requires less data or even no data at all,
448 		 * hence we always have to allocate the max.
449 		 */
450 		new_entry->action_data = calloc(1, table->params.action_data_size);
451 		if (!new_entry->action_data)
452 			goto error;
453 
454 		if (a->data_size)
455 			memcpy(new_entry->action_data,
456 			       entry->action_data,
457 			       a->data_size);
458 	}
459 
460 	return new_entry;
461 
462 error:
463 	table_entry_free(new_entry);
464 	return NULL;
465 }
466 
467 static int
468 table_entry_keycmp(struct table *table,
469 		   struct rte_swx_table_entry *e0,
470 		   struct rte_swx_table_entry *e1)
471 {
472 	uint32_t key_size = table->params.key_size;
473 	uint32_t i;
474 
475 	for (i = 0; i < key_size; i++) {
476 		uint8_t *key_mask0 = table->params.key_mask0;
477 		uint8_t km0, km[2], k[2];
478 
479 		km0 = key_mask0 ? key_mask0[i] : 0xFF;
480 
481 		km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
482 		km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
483 
484 		k[0] = e0->key[i];
485 		k[1] = e1->key[i];
486 
487 		/* Mask comparison. */
488 		if ((km[0] & km0) != (km[1] & km0))
489 			return 1; /* Not equal. */
490 
491 		/* Value comparison. */
492 		if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
493 			return 1; /* Not equal. */
494 	}
495 
496 	return 0; /* Equal. */
497 }
498 
499 static struct rte_swx_table_entry *
500 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
501 {
502 	struct rte_swx_table_entry *e;
503 
504 	TAILQ_FOREACH(e, &table->entries, node)
505 		if (!table_entry_keycmp(table, entry, e))
506 			return e; /* Found. */
507 
508 	return NULL; /* Not found. */
509 }
510 
511 static void
512 table_entries_free(struct table *table)
513 {
514 	for ( ; ; ) {
515 		struct rte_swx_table_entry *entry;
516 
517 		entry = TAILQ_FIRST(&table->entries);
518 		if (!entry)
519 			break;
520 
521 		TAILQ_REMOVE(&table->entries, entry, node);
522 		table_entry_free(entry);
523 	}
524 }
525 
526 static struct rte_swx_table_entry *
527 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
528 {
529 	struct rte_swx_table_entry *e;
530 
531 	TAILQ_FOREACH(e, &table->pending_add, node)
532 		if (!table_entry_keycmp(table, entry, e))
533 			return e; /* Found. */
534 
535 	return NULL; /* Not found. */
536 }
537 
538 static void
539 table_pending_add_admit(struct table *table)
540 {
541 	TAILQ_CONCAT(&table->entries, &table->pending_add, node);
542 }
543 
544 static void
545 table_pending_add_free(struct table *table)
546 {
547 	for ( ; ; ) {
548 		struct rte_swx_table_entry *entry;
549 
550 		entry = TAILQ_FIRST(&table->pending_add);
551 		if (!entry)
552 			break;
553 
554 		TAILQ_REMOVE(&table->pending_add, entry, node);
555 		table_entry_free(entry);
556 	}
557 }
558 
559 static struct rte_swx_table_entry *
560 table_pending_modify0_find(struct table *table,
561 			   struct rte_swx_table_entry *entry)
562 {
563 	struct rte_swx_table_entry *e;
564 
565 	TAILQ_FOREACH(e, &table->pending_modify0, node)
566 		if (!table_entry_keycmp(table, entry, e))
567 			return e; /* Found. */
568 
569 	return NULL; /* Not found. */
570 }
571 
572 static void
573 table_pending_modify0_admit(struct table *table)
574 {
575 	TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
576 }
577 
578 static void
579 table_pending_modify0_free(struct table *table)
580 {
581 	for ( ; ; ) {
582 		struct rte_swx_table_entry *entry;
583 
584 		entry = TAILQ_FIRST(&table->pending_modify0);
585 		if (!entry)
586 			break;
587 
588 		TAILQ_REMOVE(&table->pending_modify0, entry, node);
589 		table_entry_free(entry);
590 	}
591 }
592 
593 static struct rte_swx_table_entry *
594 table_pending_modify1_find(struct table *table,
595 			   struct rte_swx_table_entry *entry)
596 {
597 	struct rte_swx_table_entry *e;
598 
599 	TAILQ_FOREACH(e, &table->pending_modify1, node)
600 		if (!table_entry_keycmp(table, entry, e))
601 			return e; /* Found. */
602 
603 	return NULL; /* Not found. */
604 }
605 
606 static void
607 table_pending_modify1_admit(struct table *table)
608 {
609 	TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
610 }
611 
612 static void
613 table_pending_modify1_free(struct table *table)
614 {
615 	for ( ; ; ) {
616 		struct rte_swx_table_entry *entry;
617 
618 		entry = TAILQ_FIRST(&table->pending_modify1);
619 		if (!entry)
620 			break;
621 
622 		TAILQ_REMOVE(&table->pending_modify1, entry, node);
623 		table_entry_free(entry);
624 	}
625 }
626 
627 static struct rte_swx_table_entry *
628 table_pending_delete_find(struct table *table,
629 			  struct rte_swx_table_entry *entry)
630 {
631 	struct rte_swx_table_entry *e;
632 
633 	TAILQ_FOREACH(e, &table->pending_delete, node)
634 		if (!table_entry_keycmp(table, entry, e))
635 			return e; /* Found. */
636 
637 	return NULL; /* Not found. */
638 }
639 
640 static void
641 table_pending_delete_admit(struct table *table)
642 {
643 	TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
644 }
645 
646 static void
647 table_pending_delete_free(struct table *table)
648 {
649 	for ( ; ; ) {
650 		struct rte_swx_table_entry *entry;
651 
652 		entry = TAILQ_FIRST(&table->pending_delete);
653 		if (!entry)
654 			break;
655 
656 		TAILQ_REMOVE(&table->pending_delete, entry, node);
657 		table_entry_free(entry);
658 	}
659 }
660 
661 static void
662 table_pending_default_free(struct table *table)
663 {
664 	if (!table->pending_default)
665 		return;
666 
667 	free(table->pending_default->action_data);
668 	free(table->pending_default);
669 	table->pending_default = NULL;
670 }
671 
672 static int
673 table_is_update_pending(struct table *table, int consider_pending_default)
674 {
675 	struct rte_swx_table_entry *e;
676 	uint32_t n = 0;
677 
678 	/* Pending add. */
679 	TAILQ_FOREACH(e, &table->pending_add, node)
680 		n++;
681 
682 	/* Pending modify. */
683 	TAILQ_FOREACH(e, &table->pending_modify1, node)
684 		n++;
685 
686 	/* Pending delete. */
687 	TAILQ_FOREACH(e, &table->pending_delete, node)
688 		n++;
689 
690 	/* Pending default. */
691 	if (consider_pending_default && table->pending_default)
692 		n++;
693 
694 	return n;
695 }
696 
697 static void
698 table_free(struct rte_swx_ctl_pipeline *ctl)
699 {
700 	uint32_t i;
701 
702 	if (!ctl->tables)
703 		return;
704 
705 	for (i = 0; i < ctl->info.n_tables; i++) {
706 		struct table *table = &ctl->tables[i];
707 
708 		free(table->mf);
709 		free(table->actions);
710 		free(table->params.key_mask0);
711 
712 		table_entries_free(table);
713 		table_pending_add_free(table);
714 		table_pending_modify0_free(table);
715 		table_pending_modify1_free(table);
716 		table_pending_delete_free(table);
717 		table_pending_default_free(table);
718 	}
719 
720 	free(ctl->tables);
721 	ctl->tables = NULL;
722 }
723 
724 static void
725 selector_group_members_free(struct selector *s, uint32_t group_id)
726 {
727 	struct rte_swx_table_selector_group *group = s->groups[group_id];
728 
729 	if (!group)
730 		return;
731 
732 	for ( ; ; ) {
733 		struct rte_swx_table_selector_member *m;
734 
735 		m = TAILQ_FIRST(&group->members);
736 		if (!m)
737 			break;
738 
739 		TAILQ_REMOVE(&group->members, m, node);
740 		free(m);
741 	}
742 
743 	free(group);
744 	s->groups[group_id] = NULL;
745 }
746 
747 static void
748 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
749 {
750 	struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
751 
752 	if (!group)
753 		return;
754 
755 	for ( ; ; ) {
756 		struct rte_swx_table_selector_member *m;
757 
758 		m = TAILQ_FIRST(&group->members);
759 		if (!m)
760 			break;
761 
762 		TAILQ_REMOVE(&group->members, m, node);
763 		free(m);
764 	}
765 
766 	free(group);
767 	s->pending_groups[group_id] = NULL;
768 }
769 
770 static int
771 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
772 {
773 	struct rte_swx_table_selector_group *g, *gp;
774 	struct rte_swx_table_selector_member *m;
775 
776 	selector_pending_group_members_free(s, group_id);
777 
778 	g = s->groups[group_id];
779 	gp = s->pending_groups[group_id];
780 
781 	if (!gp) {
782 		gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
783 		if (!gp)
784 			goto error;
785 
786 		TAILQ_INIT(&gp->members);
787 
788 		s->pending_groups[group_id] = gp;
789 	}
790 
791 	if (!g)
792 		return 0;
793 
794 	TAILQ_FOREACH(m, &g->members, node) {
795 		struct rte_swx_table_selector_member *mp;
796 
797 		mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
798 		if (!mp)
799 			goto error;
800 
801 		memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
802 
803 		TAILQ_INSERT_TAIL(&gp->members, mp, node);
804 	}
805 
806 	return 0;
807 
808 error:
809 	selector_pending_group_members_free(s, group_id);
810 	return -ENOMEM;
811 }
812 
813 static void
814 selector_free(struct rte_swx_ctl_pipeline *ctl)
815 {
816 	uint32_t i;
817 
818 	if (!ctl->selectors)
819 		return;
820 
821 	for (i = 0; i < ctl->info.n_selectors; i++) {
822 		struct selector *s = &ctl->selectors[i];
823 		uint32_t i;
824 
825 		/* selector_fields. */
826 		free(s->selector_fields);
827 
828 		/* groups. */
829 		if (s->groups)
830 			for (i = 0; i < s->info.n_groups_max; i++)
831 				selector_group_members_free(s, i);
832 
833 		free(s->groups);
834 
835 		/* pending_groups. */
836 		if (s->pending_groups)
837 			for (i = 0; i < s->info.n_groups_max; i++)
838 				selector_pending_group_members_free(s, i);
839 
840 		free(s->pending_groups);
841 
842 		/* groups_added. */
843 		free(s->groups_added);
844 
845 		/* groups_pending_delete. */
846 		free(s->groups_pending_delete);
847 
848 		/* params. */
849 		free(s->params.selector_mask);
850 	}
851 
852 	free(ctl->selectors);
853 	ctl->selectors = NULL;
854 }
855 
856 static struct selector *
857 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
858 {
859 	uint32_t i;
860 
861 	for (i = 0; i < ctl->info.n_selectors; i++) {
862 		struct selector *s = &ctl->selectors[i];
863 
864 		if (!strcmp(selector_name, s->info.name))
865 			return s;
866 	}
867 
868 	return NULL;
869 }
870 
871 static int
872 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
873 {
874 	struct selector *s = &ctl->selectors[selector_id];
875 	struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
876 	uint8_t *selector_mask = NULL;
877 	uint32_t selector_size = 0, selector_offset = 0, i;
878 
879 	/* Find first (smallest offset) and last (biggest offset) match fields. */
880 	first = &s->selector_fields[0];
881 	last = &s->selector_fields[0];
882 
883 	for (i = 1; i < s->info.n_selector_fields; i++) {
884 		struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
885 
886 		if (f->offset < first->offset)
887 			first = f;
888 
889 		if (f->offset > last->offset)
890 			last = f;
891 	}
892 
893 	/* selector_offset. */
894 	selector_offset = first->offset / 8;
895 
896 	/* selector_size. */
897 	selector_size = (last->offset + last->n_bits - first->offset) / 8;
898 
899 	/* selector_mask. */
900 	selector_mask = calloc(1, selector_size);
901 	if (!selector_mask)
902 		return -ENOMEM;
903 
904 	for (i = 0; i < s->info.n_selector_fields; i++) {
905 		struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
906 		uint32_t start;
907 		size_t size;
908 
909 		start = (f->offset - first->offset) / 8;
910 		size = f->n_bits / 8;
911 
912 		memset(&selector_mask[start], 0xFF, size);
913 	}
914 
915 	/* Fill in. */
916 	s->params.group_id_offset = s->group_id_field.offset / 8;
917 	s->params.selector_size = selector_size;
918 	s->params.selector_offset = selector_offset;
919 	s->params.selector_mask = selector_mask;
920 	s->params.member_id_offset = s->member_id_field.offset / 8;
921 	s->params.n_groups_max = s->info.n_groups_max;
922 	s->params.n_members_per_group_max = s->info.n_members_per_group_max;
923 
924 	return 0;
925 }
926 
927 static void
928 table_state_free(struct rte_swx_ctl_pipeline *ctl)
929 {
930 	uint32_t i;
931 
932 	if (!ctl->ts_next)
933 		return;
934 
935 	/* For each table, free its table state. */
936 	for (i = 0; i < ctl->info.n_tables; i++) {
937 		struct table *table = &ctl->tables[i];
938 		struct rte_swx_table_state *ts = &ctl->ts_next[i];
939 
940 		/* Default action data. */
941 		free(ts->default_action_data);
942 
943 		/* Table object. */
944 		if (!table->is_stub && table->ops.free && ts->obj)
945 			table->ops.free(ts->obj);
946 	}
947 
948 	/* For each selector table, free its table state. */
949 	for (i = 0; i < ctl->info.n_selectors; i++) {
950 		struct rte_swx_table_state *ts = &ctl->ts_next[i];
951 
952 		/* Table object. */
953 		if (ts->obj)
954 			rte_swx_table_selector_free(ts->obj);
955 	}
956 
957 	free(ctl->ts_next);
958 	ctl->ts_next = NULL;
959 }
960 
961 static int
962 table_state_create(struct rte_swx_ctl_pipeline *ctl)
963 {
964 	int status = 0;
965 	uint32_t i;
966 
967 	ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
968 			      sizeof(struct rte_swx_table_state));
969 	if (!ctl->ts_next) {
970 		status = -ENOMEM;
971 		goto error;
972 	}
973 
974 	/* Tables. */
975 	for (i = 0; i < ctl->info.n_tables; i++) {
976 		struct table *table = &ctl->tables[i];
977 		struct rte_swx_table_state *ts = &ctl->ts[i];
978 		struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
979 
980 		/* Table object. */
981 		if (!table->is_stub && table->ops.add) {
982 			ts_next->obj = table->ops.create(&table->params,
983 							 &table->entries,
984 							 table->info.args,
985 							 ctl->numa_node);
986 			if (!ts_next->obj) {
987 				status = -ENODEV;
988 				goto error;
989 			}
990 		}
991 
992 		if (!table->is_stub && !table->ops.add)
993 			ts_next->obj = ts->obj;
994 
995 		/* Default action data: duplicate from current table state. */
996 		ts_next->default_action_data =
997 			malloc(table->params.action_data_size);
998 		if (!ts_next->default_action_data) {
999 			status = -ENOMEM;
1000 			goto error;
1001 		}
1002 
1003 		memcpy(ts_next->default_action_data,
1004 		       ts->default_action_data,
1005 		       table->params.action_data_size);
1006 
1007 		ts_next->default_action_id = ts->default_action_id;
1008 	}
1009 
1010 	/* Selector tables. */
1011 	for (i = 0; i < ctl->info.n_selectors; i++) {
1012 		struct selector *s = &ctl->selectors[i];
1013 		struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
1014 
1015 		/* Table object. */
1016 		ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1017 		if (!ts_next->obj) {
1018 			status = -ENODEV;
1019 			goto error;
1020 		}
1021 	}
1022 
1023 	return 0;
1024 
1025 error:
1026 	table_state_free(ctl);
1027 	return status;
1028 }
1029 
1030 void
1031 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1032 {
1033 	if (!ctl)
1034 		return;
1035 
1036 	action_free(ctl);
1037 
1038 	table_state_free(ctl);
1039 
1040 	selector_free(ctl);
1041 
1042 	table_free(ctl);
1043 
1044 	free(ctl);
1045 }
1046 
1047 struct rte_swx_ctl_pipeline *
1048 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1049 {
1050 	struct rte_swx_ctl_pipeline *ctl = NULL;
1051 	uint32_t i;
1052 	int status;
1053 
1054 	if (!p)
1055 		goto error;
1056 
1057 	ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1058 	if (!ctl)
1059 		goto error;
1060 
1061 	/* info. */
1062 	status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1063 	if (status)
1064 		goto error;
1065 
1066 	/* numa_node. */
1067 	status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1068 	if (status)
1069 		goto error;
1070 
1071 	/* p. */
1072 	ctl->p = p;
1073 
1074 	/* actions. */
1075 	ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1076 	if (!ctl->actions)
1077 		goto error;
1078 
1079 	for (i = 0; i < ctl->info.n_actions; i++) {
1080 		struct action *a = &ctl->actions[i];
1081 		uint32_t j;
1082 
1083 		/* info. */
1084 		status = rte_swx_ctl_action_info_get(p, i, &a->info);
1085 		if (status)
1086 			goto error;
1087 
1088 		/* args. */
1089 		a->args = calloc(a->info.n_args,
1090 				 sizeof(struct rte_swx_ctl_action_arg_info));
1091 		if (!a->args)
1092 			goto error;
1093 
1094 		for (j = 0; j < a->info.n_args; j++) {
1095 			status = rte_swx_ctl_action_arg_info_get(p,
1096 								 i,
1097 								 j,
1098 								 &a->args[j]);
1099 			if (status)
1100 				goto error;
1101 		}
1102 
1103 		/* data_size. */
1104 		for (j = 0; j < a->info.n_args; j++) {
1105 			struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1106 
1107 			a->data_size += info->n_bits;
1108 		}
1109 
1110 		a->data_size = (a->data_size + 7) / 8;
1111 	}
1112 
1113 	/* tables. */
1114 	ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1115 	if (!ctl->tables)
1116 		goto error;
1117 
1118 	for (i = 0; i < ctl->info.n_tables; i++) {
1119 		struct table *t = &ctl->tables[i];
1120 
1121 		TAILQ_INIT(&t->entries);
1122 		TAILQ_INIT(&t->pending_add);
1123 		TAILQ_INIT(&t->pending_modify0);
1124 		TAILQ_INIT(&t->pending_modify1);
1125 		TAILQ_INIT(&t->pending_delete);
1126 	}
1127 
1128 	for (i = 0; i < ctl->info.n_tables; i++) {
1129 		struct table *t = &ctl->tables[i];
1130 		uint32_t j;
1131 
1132 		/* info. */
1133 		status = rte_swx_ctl_table_info_get(p, i, &t->info);
1134 		if (status)
1135 			goto error;
1136 
1137 		/* mf. */
1138 		t->mf = calloc(t->info.n_match_fields,
1139 			sizeof(struct rte_swx_ctl_table_match_field_info));
1140 		if (!t->mf)
1141 			goto error;
1142 
1143 		for (j = 0; j < t->info.n_match_fields; j++) {
1144 			status = rte_swx_ctl_table_match_field_info_get(p,
1145 				i,
1146 				j,
1147 				&t->mf[j]);
1148 			if (status)
1149 				goto error;
1150 		}
1151 
1152 		/* actions. */
1153 		t->actions = calloc(t->info.n_actions,
1154 			sizeof(struct rte_swx_ctl_table_action_info));
1155 		if (!t->actions)
1156 			goto error;
1157 
1158 		for (j = 0; j < t->info.n_actions; j++) {
1159 			status = rte_swx_ctl_table_action_info_get(p,
1160 				i,
1161 				j,
1162 				&t->actions[j]);
1163 			if (status ||
1164 			    t->actions[j].action_id >= ctl->info.n_actions)
1165 				goto error;
1166 		}
1167 
1168 		/* ops, is_stub. */
1169 		status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1170 		if (status)
1171 			goto error;
1172 
1173 		if ((t->is_stub && t->info.n_match_fields) ||
1174 		    (!t->is_stub && !t->info.n_match_fields))
1175 			goto error;
1176 
1177 		/* params. */
1178 		status = table_params_get(ctl, i);
1179 		if (status)
1180 			goto error;
1181 	}
1182 
1183 	/* selector tables. */
1184 	ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1185 	if (!ctl->selectors)
1186 		goto error;
1187 
1188 	for (i = 0; i < ctl->info.n_selectors; i++) {
1189 		struct selector *s = &ctl->selectors[i];
1190 		uint32_t j;
1191 
1192 		/* info. */
1193 		status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1194 		if (status)
1195 			goto error;
1196 
1197 		/* group_id field. */
1198 		status = rte_swx_ctl_selector_group_id_field_info_get(p,
1199 			i,
1200 			&s->group_id_field);
1201 		if (status)
1202 			goto error;
1203 
1204 		/* selector fields. */
1205 		s->selector_fields = calloc(s->info.n_selector_fields,
1206 			sizeof(struct rte_swx_ctl_table_match_field_info));
1207 		if (!s->selector_fields)
1208 			goto error;
1209 
1210 		for (j = 0; j < s->info.n_selector_fields; j++) {
1211 			status = rte_swx_ctl_selector_field_info_get(p,
1212 				i,
1213 				j,
1214 				&s->selector_fields[j]);
1215 			if (status)
1216 				goto error;
1217 		}
1218 
1219 		/* member_id field. */
1220 		status = rte_swx_ctl_selector_member_id_field_info_get(p,
1221 			i,
1222 			&s->member_id_field);
1223 		if (status)
1224 			goto error;
1225 
1226 		/* groups. */
1227 		s->groups = calloc(s->info.n_groups_max,
1228 			sizeof(struct rte_swx_table_selector_group *));
1229 		if (!s->groups)
1230 			goto error;
1231 
1232 		/* pending_groups. */
1233 		s->pending_groups = calloc(s->info.n_groups_max,
1234 			sizeof(struct rte_swx_table_selector_group *));
1235 		if (!s->pending_groups)
1236 			goto error;
1237 
1238 		/* groups_added. */
1239 		s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1240 		if (!s->groups_added)
1241 			goto error;
1242 
1243 		/* groups_pending_delete. */
1244 		s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1245 		if (!s->groups_pending_delete)
1246 			goto error;
1247 
1248 		/* params. */
1249 		status = selector_params_get(ctl, i);
1250 		if (status)
1251 			goto error;
1252 	}
1253 
1254 	/* ts. */
1255 	status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1256 	if (status)
1257 		goto error;
1258 
1259 	/* ts_next. */
1260 	status = table_state_create(ctl);
1261 	if (status)
1262 		goto error;
1263 
1264 	return ctl;
1265 
1266 error:
1267 	rte_swx_ctl_pipeline_free(ctl);
1268 	return NULL;
1269 }
1270 
1271 int
1272 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1273 				     const char *table_name,
1274 				     struct rte_swx_table_entry *entry)
1275 {
1276 	struct table *table;
1277 	struct rte_swx_table_entry *new_entry, *existing_entry;
1278 	uint32_t table_id;
1279 
1280 	CHECK(ctl, EINVAL);
1281 	CHECK(table_name && table_name[0], EINVAL);
1282 
1283 	table = table_find(ctl, table_name);
1284 	CHECK(table, EINVAL);
1285 	table_id = table - ctl->tables;
1286 
1287 	CHECK(entry, EINVAL);
1288 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1289 
1290 	new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1291 	CHECK(new_entry, ENOMEM);
1292 
1293 	/* The new entry is found in the table->entries list:
1294 	 * - Add the new entry to the table->pending_modify1 list;
1295 	 * - Move the existing entry from the table->entries list to the
1296 	 *   table->pending_modify0 list.
1297 	 */
1298 	existing_entry = table_entries_find(table, entry);
1299 	if (existing_entry) {
1300 		TAILQ_INSERT_TAIL(&table->pending_modify1,
1301 				  new_entry,
1302 				  node);
1303 
1304 		TAILQ_REMOVE(&table->entries,
1305 			     existing_entry,
1306 			     node);
1307 
1308 		TAILQ_INSERT_TAIL(&table->pending_modify0,
1309 				  existing_entry,
1310 				  node);
1311 
1312 		return 0;
1313 	}
1314 
1315 	/* The new entry is found in the table->pending_add list:
1316 	 * - Replace the entry in the table->pending_add list with the new entry
1317 	 *   (and free the replaced entry).
1318 	 */
1319 	existing_entry = table_pending_add_find(table, entry);
1320 	if (existing_entry) {
1321 		TAILQ_INSERT_AFTER(&table->pending_add,
1322 				   existing_entry,
1323 				   new_entry,
1324 				   node);
1325 
1326 		TAILQ_REMOVE(&table->pending_add,
1327 			     existing_entry,
1328 			     node);
1329 
1330 		table_entry_free(existing_entry);
1331 
1332 		return 0;
1333 	}
1334 
1335 	/* The new entry is found in the table->pending_modify1 list:
1336 	 * - Replace the entry in the table->pending_modify1 list with the new
1337 	 *   entry (and free the replaced entry).
1338 	 */
1339 	existing_entry = table_pending_modify1_find(table, entry);
1340 	if (existing_entry) {
1341 		TAILQ_INSERT_AFTER(&table->pending_modify1,
1342 				   existing_entry,
1343 				   new_entry,
1344 				   node);
1345 
1346 		TAILQ_REMOVE(&table->pending_modify1,
1347 			     existing_entry,
1348 			     node);
1349 
1350 		table_entry_free(existing_entry);
1351 
1352 		return 0;
1353 	}
1354 
1355 	/* The new entry is found in the table->pending_delete list:
1356 	 * - Add the new entry to the table->pending_modify1 list;
1357 	 * - Move the existing entry from the table->pending_delete list to the
1358 	 *   table->pending_modify0 list.
1359 	 */
1360 	existing_entry = table_pending_delete_find(table, entry);
1361 	if (existing_entry) {
1362 		TAILQ_INSERT_TAIL(&table->pending_modify1,
1363 				  new_entry,
1364 				  node);
1365 
1366 		TAILQ_REMOVE(&table->pending_delete,
1367 			     existing_entry,
1368 			     node);
1369 
1370 		TAILQ_INSERT_TAIL(&table->pending_modify0,
1371 				  existing_entry,
1372 				  node);
1373 
1374 		return 0;
1375 	}
1376 
1377 	/* The new entry is not found in any of the above lists:
1378 	 * - Add the new entry to the table->pending_add list.
1379 	 */
1380 	TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1381 
1382 	return 0;
1383 }
1384 
1385 int
1386 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1387 					const char *table_name,
1388 					struct rte_swx_table_entry *entry)
1389 {
1390 	struct table *table;
1391 	struct rte_swx_table_entry *existing_entry;
1392 	uint32_t table_id;
1393 
1394 	CHECK(ctl, EINVAL);
1395 
1396 	CHECK(table_name && table_name[0], EINVAL);
1397 	table = table_find(ctl, table_name);
1398 	CHECK(table, EINVAL);
1399 	table_id = table - ctl->tables;
1400 
1401 	CHECK(entry, EINVAL);
1402 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1403 
1404 	/* The entry is found in the table->entries list:
1405 	 * - Move the existing entry from the table->entries list to to the
1406 	 *   table->pending_delete list.
1407 	 */
1408 	existing_entry = table_entries_find(table, entry);
1409 	if (existing_entry) {
1410 		TAILQ_REMOVE(&table->entries,
1411 			     existing_entry,
1412 			     node);
1413 
1414 		TAILQ_INSERT_TAIL(&table->pending_delete,
1415 				  existing_entry,
1416 				  node);
1417 
1418 		return 0;
1419 	}
1420 
1421 	/* The entry is found in the table->pending_add list:
1422 	 * - Remove the entry from the table->pending_add list and free it.
1423 	 */
1424 	existing_entry = table_pending_add_find(table, entry);
1425 	if (existing_entry) {
1426 		TAILQ_REMOVE(&table->pending_add,
1427 			     existing_entry,
1428 			     node);
1429 
1430 		table_entry_free(existing_entry);
1431 	}
1432 
1433 	/* The entry is found in the table->pending_modify1 list:
1434 	 * - Free the entry in the table->pending_modify1 list;
1435 	 * - Move the existing entry from the table->pending_modify0 list to the
1436 	 *   table->pending_delete list.
1437 	 */
1438 	existing_entry = table_pending_modify1_find(table, entry);
1439 	if (existing_entry) {
1440 		struct rte_swx_table_entry *real_existing_entry;
1441 
1442 		TAILQ_REMOVE(&table->pending_modify1,
1443 			     existing_entry,
1444 			     node);
1445 
1446 		table_entry_free(existing_entry);
1447 
1448 		real_existing_entry = table_pending_modify0_find(table, entry);
1449 		CHECK(real_existing_entry, EINVAL); /* Coverity. */
1450 
1451 		TAILQ_REMOVE(&table->pending_modify0,
1452 			     real_existing_entry,
1453 			     node);
1454 
1455 		TAILQ_INSERT_TAIL(&table->pending_delete,
1456 				  real_existing_entry,
1457 				  node);
1458 
1459 		return 0;
1460 	}
1461 
1462 	/* The entry is found in the table->pending_delete list:
1463 	 * - Do nothing: the existing entry is already in the
1464 	 *   table->pending_delete list, i.e. already marked for delete, so
1465 	 *   simply keep it there as it is.
1466 	 */
1467 
1468 	/* The entry is not found in any of the above lists:
1469 	 * - Do nothing: no existing entry to delete.
1470 	 */
1471 
1472 	return 0;
1473 }
1474 
1475 int
1476 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1477 					     const char *table_name,
1478 					     struct rte_swx_table_entry *entry)
1479 {
1480 	struct table *table;
1481 	struct rte_swx_table_entry *new_entry;
1482 	uint32_t table_id;
1483 
1484 	CHECK(ctl, EINVAL);
1485 
1486 	CHECK(table_name && table_name[0], EINVAL);
1487 	table = table_find(ctl, table_name);
1488 	CHECK(table, EINVAL);
1489 	table_id = table - ctl->tables;
1490 	CHECK(!table->info.default_action_is_const, EINVAL);
1491 
1492 	CHECK(entry, EINVAL);
1493 	CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1494 
1495 	new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1496 	CHECK(new_entry, ENOMEM);
1497 
1498 	table_pending_default_free(table);
1499 
1500 	table->pending_default = new_entry;
1501 	return 0;
1502 }
1503 
1504 
1505 static void
1506 table_entry_list_free(struct rte_swx_table_entry_list *list)
1507 {
1508 	for ( ; ; ) {
1509 		struct rte_swx_table_entry *entry;
1510 
1511 		entry = TAILQ_FIRST(list);
1512 		if (!entry)
1513 			break;
1514 
1515 		TAILQ_REMOVE(list, entry, node);
1516 		table_entry_free(entry);
1517 	}
1518 }
1519 
1520 static int
1521 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1522 			   uint32_t table_id,
1523 			   struct rte_swx_table_entry_list *dst,
1524 			   struct rte_swx_table_entry_list *src)
1525 {
1526 	struct rte_swx_table_entry *src_entry;
1527 
1528 	TAILQ_FOREACH(src_entry, src, node) {
1529 		struct rte_swx_table_entry *dst_entry;
1530 
1531 		dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1532 		if (!dst_entry)
1533 			goto error;
1534 
1535 		TAILQ_INSERT_TAIL(dst, dst_entry, node);
1536 	}
1537 
1538 	return 0;
1539 
1540 error:
1541 	table_entry_list_free(dst);
1542 	return -ENOMEM;
1543 }
1544 
1545 /* This commit stage contains all the operations that can fail; in case ANY of
1546  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1547  */
1548 static int
1549 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1550 	       uint32_t table_id,
1551 	       uint32_t after_swap)
1552 {
1553 	struct table *table = &ctl->tables[table_id];
1554 	struct rte_swx_table_state *ts = &ctl->ts[table_id];
1555 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1556 
1557 	if (table->is_stub || !table_is_update_pending(table, 0))
1558 		return 0;
1559 
1560 	/*
1561 	 * Current table supports incremental update.
1562 	 */
1563 	if (table->ops.add) {
1564 		/* Reset counters. */
1565 		table->n_add = 0;
1566 		table->n_modify = 0;
1567 		table->n_delete = 0;
1568 
1569 		/* Add pending rules. */
1570 		struct rte_swx_table_entry *entry;
1571 
1572 		TAILQ_FOREACH(entry, &table->pending_add, node) {
1573 			int status;
1574 
1575 			status = table->ops.add(ts_next->obj, entry);
1576 			if (status)
1577 				return status;
1578 
1579 			table->n_add++;
1580 		}
1581 
1582 		/* Modify pending rules. */
1583 		TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1584 			int status;
1585 
1586 			status = table->ops.add(ts_next->obj, entry);
1587 			if (status)
1588 				return status;
1589 
1590 			table->n_modify++;
1591 		}
1592 
1593 		/* Delete pending rules. */
1594 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
1595 			int status;
1596 
1597 			status = table->ops.del(ts_next->obj, entry);
1598 			if (status)
1599 				return status;
1600 
1601 			table->n_delete++;
1602 		}
1603 
1604 		return 0;
1605 	}
1606 
1607 	/*
1608 	 * Current table does NOT support incremental update.
1609 	 */
1610 	if (!after_swap) {
1611 		struct rte_swx_table_entry_list list;
1612 		int status;
1613 
1614 		/* Create updated list of entries included. */
1615 		TAILQ_INIT(&list);
1616 
1617 		status = table_entry_list_duplicate(ctl,
1618 						    table_id,
1619 						    &list,
1620 						    &table->entries);
1621 		if (status)
1622 			goto error;
1623 
1624 		status = table_entry_list_duplicate(ctl,
1625 						    table_id,
1626 						    &list,
1627 						    &table->pending_add);
1628 		if (status)
1629 			goto error;
1630 
1631 		status = table_entry_list_duplicate(ctl,
1632 						    table_id,
1633 						    &list,
1634 						    &table->pending_modify1);
1635 		if (status)
1636 			goto error;
1637 
1638 		/* Create new table object with the updates included. */
1639 		ts_next->obj = table->ops.create(&table->params,
1640 						 &list,
1641 						 table->info.args,
1642 						 ctl->numa_node);
1643 		if (!ts_next->obj) {
1644 			status = -ENODEV;
1645 			goto error;
1646 		}
1647 
1648 		table_entry_list_free(&list);
1649 
1650 		return 0;
1651 
1652 error:
1653 		table_entry_list_free(&list);
1654 		return status;
1655 	}
1656 
1657 	/* Free the old table object. */
1658 	if (ts_next->obj && table->ops.free)
1659 		table->ops.free(ts_next->obj);
1660 
1661 	/* Copy over the new table object. */
1662 	ts_next->obj = ts->obj;
1663 
1664 	return 0;
1665 }
1666 
1667 /* This commit stage contains all the operations that cannot fail. They are
1668  * executed only if the previous stage was successful for ALL the tables. Hence,
1669  * none of these operations has to be rolled back for ANY table.
1670  */
1671 static void
1672 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1673 {
1674 	struct table *table = &ctl->tables[table_id];
1675 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1676 	struct action *a;
1677 	uint8_t *action_data;
1678 	uint64_t action_id;
1679 
1680 	/* Copy the pending default entry. */
1681 	if (!table->pending_default)
1682 		return;
1683 
1684 	action_id = table->pending_default->action_id;
1685 	action_data = table->pending_default->action_data;
1686 	a = &ctl->actions[action_id];
1687 
1688 	memcpy(ts_next->default_action_data,
1689 	       action_data,
1690 	       a->data_size);
1691 
1692 	ts_next->default_action_id = action_id;
1693 }
1694 
1695 /* This last commit stage is simply finalizing a successful commit operation.
1696  * This stage is only executed if all the previous stages were successful. This
1697  * stage cannot fail.
1698  */
1699 static void
1700 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1701 {
1702 	struct table *table = &ctl->tables[table_id];
1703 
1704 	/* Move all the pending add entries to the table, as they are now part
1705 	 * of the table.
1706 	 */
1707 	table_pending_add_admit(table);
1708 
1709 	/* Move all the pending modify1 entries to table, are they are now part
1710 	 * of the table. Free up all the pending modify0 entries, as they are no
1711 	 * longer part of the table.
1712 	 */
1713 	table_pending_modify1_admit(table);
1714 	table_pending_modify0_free(table);
1715 
1716 	/* Free up all the pending delete entries, as they are no longer part of
1717 	 * the table.
1718 	 */
1719 	table_pending_delete_free(table);
1720 
1721 	/* Free up the pending default entry, as it is now part of the table. */
1722 	table_pending_default_free(table);
1723 }
1724 
1725 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1726  * commit operations that can fail did fail for ANY table. It reverts ALL the
1727  * tables to their state before the commit started, as if the commit never
1728  * happened.
1729  */
1730 static void
1731 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1732 {
1733 	struct table *table = &ctl->tables[table_id];
1734 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1735 
1736 	if (table->is_stub || !table_is_update_pending(table, 0))
1737 		return;
1738 
1739 	if (table->ops.add) {
1740 		struct rte_swx_table_entry *entry;
1741 
1742 		/* Add back all the entries that were just deleted. */
1743 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
1744 			if (!table->n_delete)
1745 				break;
1746 
1747 			table->ops.add(ts_next->obj, entry);
1748 			table->n_delete--;
1749 		}
1750 
1751 		/* Add back the old copy for all the entries that were just
1752 		 * modified.
1753 		 */
1754 		TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1755 			if (!table->n_modify)
1756 				break;
1757 
1758 			table->ops.add(ts_next->obj, entry);
1759 			table->n_modify--;
1760 		}
1761 
1762 		/* Delete all the entries that were just added. */
1763 		TAILQ_FOREACH(entry, &table->pending_add, node) {
1764 			if (!table->n_add)
1765 				break;
1766 
1767 			table->ops.del(ts_next->obj, entry);
1768 			table->n_add--;
1769 		}
1770 	} else {
1771 		struct rte_swx_table_state *ts = &ctl->ts[table_id];
1772 
1773 		/* Free the new table object, as update was cancelled. */
1774 		if (ts_next->obj && table->ops.free)
1775 			table->ops.free(ts_next->obj);
1776 
1777 		/* Reinstate the old table object. */
1778 		ts_next->obj = ts->obj;
1779 	}
1780 }
1781 
1782 /* This stage is conditionally executed (as instructed by the user) after a
1783  * failed commit operation to remove ALL the pending work for ALL the tables.
1784  */
1785 static void
1786 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1787 {
1788 	struct table *table = &ctl->tables[table_id];
1789 
1790 	/* Free up all the pending add entries, as none of them is part of the
1791 	 * table.
1792 	 */
1793 	table_pending_add_free(table);
1794 
1795 	/* Free up all the pending modify1 entries, as none of them made it to
1796 	 * the table. Add back all the pending modify0 entries, as none of them
1797 	 * was deleted from the table.
1798 	 */
1799 	table_pending_modify1_free(table);
1800 	table_pending_modify0_admit(table);
1801 
1802 	/* Add back all the pending delete entries, as none of them was deleted
1803 	 * from the table.
1804 	 */
1805 	table_pending_delete_admit(table);
1806 
1807 	/* Free up the pending default entry, as it is no longer going to be
1808 	 * added to the table.
1809 	 */
1810 	table_pending_default_free(table);
1811 }
1812 
1813 int
1814 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1815 					const char *selector_name,
1816 					uint32_t *group_id)
1817 {
1818 	struct selector *s;
1819 	uint32_t i;
1820 
1821 	/* Check input arguments. */
1822 	if (!ctl || !selector_name || !selector_name[0] || !group_id)
1823 		return -EINVAL;
1824 
1825 	s = selector_find(ctl, selector_name);
1826 	if (!s)
1827 		return -EINVAL;
1828 
1829 	/* Find an unused group. */
1830 	for (i = 0; i < s->info.n_groups_max; i++)
1831 		if (!s->groups_added[i]) {
1832 			*group_id = i;
1833 			s->groups_added[i] = 1;
1834 			return 0;
1835 		}
1836 
1837 	return -ENOSPC;
1838 }
1839 
1840 int
1841 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
1842 					   const char *selector_name,
1843 					   uint32_t group_id)
1844 {
1845 	struct selector *s;
1846 	struct rte_swx_table_selector_group *group;
1847 
1848 	/* Check input arguments. */
1849 	if (!ctl || !selector_name || !selector_name[0])
1850 		return -EINVAL;
1851 
1852 	s = selector_find(ctl, selector_name);
1853 	if (!s ||
1854 	   (group_id >= s->info.n_groups_max) ||
1855 	   !s->groups_added[group_id])
1856 		return -EINVAL;
1857 
1858 	/* Check if this group is already scheduled for deletion. */
1859 	if (s->groups_pending_delete[group_id])
1860 		return 0;
1861 
1862 	/* Initialize the pending group, if needed. */
1863 	if (!s->pending_groups[group_id]) {
1864 		int status;
1865 
1866 		status = selector_group_duplicate_to_pending(s, group_id);
1867 		if (status)
1868 			return status;
1869 	}
1870 
1871 	group = s->pending_groups[group_id];
1872 
1873 	/* Schedule removal of all the members from the current group. */
1874 	for ( ; ; ) {
1875 		struct rte_swx_table_selector_member *m;
1876 
1877 		m = TAILQ_FIRST(&group->members);
1878 		if (!m)
1879 			break;
1880 
1881 		TAILQ_REMOVE(&group->members, m, node);
1882 		free(m);
1883 	}
1884 
1885 	/* Schedule the group for deletion. */
1886 	s->groups_pending_delete[group_id] = 1;
1887 
1888 	return 0;
1889 }
1890 
1891 int
1892 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
1893 					       const char *selector_name,
1894 					       uint32_t group_id,
1895 					       uint32_t member_id,
1896 					       uint32_t member_weight)
1897 {
1898 	struct selector *s;
1899 	struct rte_swx_table_selector_group *group;
1900 	struct rte_swx_table_selector_member *m;
1901 
1902 	if (!member_weight)
1903 		return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
1904 									 selector_name,
1905 									 group_id,
1906 									 member_id);
1907 
1908 	/* Check input arguments. */
1909 	if (!ctl || !selector_name || !selector_name[0])
1910 		return -EINVAL;
1911 
1912 	s = selector_find(ctl, selector_name);
1913 	if (!s ||
1914 	   (group_id >= s->info.n_groups_max) ||
1915 	   !s->groups_added[group_id] ||
1916 	   s->groups_pending_delete[group_id])
1917 		return -EINVAL;
1918 
1919 	/* Initialize the pending group, if needed. */
1920 	if (!s->pending_groups[group_id]) {
1921 		int status;
1922 
1923 		status = selector_group_duplicate_to_pending(s, group_id);
1924 		if (status)
1925 			return status;
1926 	}
1927 
1928 	group = s->pending_groups[group_id];
1929 
1930 	/* If this member is already in this group, then simply update its weight and return. */
1931 	TAILQ_FOREACH(m, &group->members, node)
1932 		if (m->member_id == member_id) {
1933 			m->member_weight = member_weight;
1934 			return 0;
1935 		}
1936 
1937 	/* Add new member to this group. */
1938 	m = calloc(1, sizeof(struct rte_swx_table_selector_member));
1939 	if (!m)
1940 		return -ENOMEM;
1941 
1942 	m->member_id = member_id;
1943 	m->member_weight = member_weight;
1944 
1945 	TAILQ_INSERT_TAIL(&group->members, m, node);
1946 
1947 	return 0;
1948 }
1949 
1950 int
1951 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
1952 						  const char *selector_name,
1953 						  uint32_t group_id __rte_unused,
1954 						  uint32_t member_id __rte_unused)
1955 {
1956 	struct selector *s;
1957 	struct rte_swx_table_selector_group *group;
1958 	struct rte_swx_table_selector_member *m;
1959 
1960 	/* Check input arguments. */
1961 	if (!ctl || !selector_name || !selector_name[0])
1962 		return -EINVAL;
1963 
1964 	s = selector_find(ctl, selector_name);
1965 	if (!s ||
1966 	    (group_id >= s->info.n_groups_max) ||
1967 	    !s->groups_added[group_id] ||
1968 	    s->groups_pending_delete[group_id])
1969 		return -EINVAL;
1970 
1971 	/* Initialize the pending group, if needed. */
1972 	if (!s->pending_groups[group_id]) {
1973 		int status;
1974 
1975 		status = selector_group_duplicate_to_pending(s, group_id);
1976 		if (status)
1977 			return status;
1978 	}
1979 
1980 	group = s->pending_groups[group_id];
1981 
1982 	/* Look for this member in the group and remove it, if found. */
1983 	TAILQ_FOREACH(m, &group->members, node)
1984 		if (m->member_id == member_id) {
1985 			TAILQ_REMOVE(&group->members, m, node);
1986 			free(m);
1987 			return 0;
1988 		}
1989 
1990 	return 0;
1991 }
1992 
1993 static int
1994 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
1995 {
1996 	struct selector *s = &ctl->selectors[selector_id];
1997 	struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
1998 	uint32_t group_id;
1999 
2000 	/* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2001 	 * mirror copy (ts_next->obj).
2002 	 */
2003 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2004 		struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2005 		int status;
2006 
2007 		/* Skip this group if no change needed. */
2008 		if (!group)
2009 			continue;
2010 
2011 		/* Apply the pending changes for the current group. */
2012 		status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2013 		if (status)
2014 			return status;
2015 	}
2016 
2017 	return 0;
2018 }
2019 
2020 static void
2021 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2022 {
2023 	struct selector *s = &ctl->selectors[selector_id];
2024 	uint32_t group_id;
2025 
2026 	/* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2027 	 * records (s->groups[group_id).
2028 	 */
2029 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2030 		struct rte_swx_table_selector_group *g = s->groups[group_id];
2031 		struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2032 
2033 		/* Skip this group if no change needed. */
2034 		if (!gp)
2035 			continue;
2036 
2037 		/* Transition the pending changes to stable. */
2038 		s->groups[group_id] = gp;
2039 		s->pending_groups[group_id] = NULL;
2040 
2041 		/* Free the old group member list. */
2042 		if (!g)
2043 			continue;
2044 
2045 		for ( ; ; ) {
2046 			struct rte_swx_table_selector_member *m;
2047 
2048 			m = TAILQ_FIRST(&g->members);
2049 			if (!m)
2050 				break;
2051 
2052 			TAILQ_REMOVE(&g->members, m, node);
2053 			free(m);
2054 		}
2055 
2056 		free(g);
2057 	}
2058 
2059 	/* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2060 	 * s->groups_added[group_id].
2061 	 */
2062 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2063 		if (s->groups_pending_delete[group_id]) {
2064 			s->groups_added[group_id] = 0;
2065 			s->groups_pending_delete[group_id] = 0;
2066 		}
2067 }
2068 
2069 static void
2070 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2071 {
2072 	struct selector *s = &ctl->selectors[selector_id];
2073 	struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2074 	struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2075 	uint32_t group_id;
2076 
2077 	/* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2078 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2079 		struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2080 
2081 		if (gp) {
2082 			ts_next->obj = ts->obj;
2083 			break;
2084 		}
2085 	}
2086 }
2087 
2088 static void
2089 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2090 {
2091 	struct selector *s = &ctl->selectors[selector_id];
2092 	uint32_t group_id;
2093 
2094 	/* Discard any pending group member changes (s->pending_groups[group_id]). */
2095 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2096 		selector_pending_group_members_free(s, group_id);
2097 
2098 	/* Discard any pending group deletions. */
2099 	memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2100 }
2101 
2102 int
2103 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2104 {
2105 	struct rte_swx_table_state *ts;
2106 	int status = 0;
2107 	uint32_t i;
2108 
2109 	CHECK(ctl, EINVAL);
2110 
2111 	/* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2112 	 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2113 	 */
2114 	for (i = 0; i < ctl->info.n_tables; i++) {
2115 		status = table_rollfwd0(ctl, i, 0);
2116 		if (status)
2117 			goto rollback;
2118 	}
2119 
2120 	for (i = 0; i < ctl->info.n_selectors; i++) {
2121 		status = selector_rollfwd(ctl, i);
2122 		if (status)
2123 			goto rollback;
2124 	}
2125 
2126 	for (i = 0; i < ctl->info.n_tables; i++)
2127 		table_rollfwd1(ctl, i);
2128 
2129 	/* Swap the table state for the data plane. The current ts and ts_next
2130 	 * become the new ts_next and ts, respectively.
2131 	 */
2132 	rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2133 	usleep(100);
2134 	ts = ctl->ts;
2135 	ctl->ts = ctl->ts_next;
2136 	ctl->ts_next = ts;
2137 
2138 	/* Operate the changes on the current ts_next, which is the previous ts, in order to get
2139 	 * the current ts_next in sync with the current ts. Since the changes that can fail did
2140 	 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2141 	 * current ts_next, hence no error checking is needed.
2142 	 */
2143 	for (i = 0; i < ctl->info.n_tables; i++) {
2144 		table_rollfwd0(ctl, i, 1);
2145 		table_rollfwd1(ctl, i);
2146 		table_rollfwd2(ctl, i);
2147 	}
2148 
2149 	for (i = 0; i < ctl->info.n_selectors; i++) {
2150 		selector_rollfwd(ctl, i);
2151 		selector_rollfwd_finalize(ctl, i);
2152 	}
2153 
2154 	return 0;
2155 
2156 rollback:
2157 	for (i = 0; i < ctl->info.n_tables; i++) {
2158 		table_rollback(ctl, i);
2159 		if (abort_on_fail)
2160 			table_abort(ctl, i);
2161 	}
2162 
2163 	for (i = 0; i < ctl->info.n_selectors; i++) {
2164 		selector_rollback(ctl, i);
2165 		if (abort_on_fail)
2166 			selector_abort(ctl, i);
2167 	}
2168 
2169 	return status;
2170 }
2171 
2172 void
2173 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2174 {
2175 	uint32_t i;
2176 
2177 	if (!ctl)
2178 		return;
2179 
2180 	for (i = 0; i < ctl->info.n_tables; i++)
2181 		table_abort(ctl, i);
2182 
2183 	for (i = 0; i < ctl->info.n_selectors; i++)
2184 		selector_abort(ctl, i);
2185 }
2186 
2187 static int
2188 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2189 {
2190 	uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2191 
2192 	if (!mask) {
2193 		*prefix_length = 0;
2194 		return 0;
2195 	}
2196 
2197 	/* Count trailing zero bits. */
2198 	for (i = 0; i < 64; i++) {
2199 		if (mask & (1LLU << i))
2200 			break;
2201 
2202 		n_trailing_zeros++;
2203 	}
2204 
2205 	/* Count the one bits that follow. */
2206 	for ( ; i < 64; i++) {
2207 		if (!(mask & (1LLU << i)))
2208 			break;
2209 
2210 		n_ones++;
2211 	}
2212 
2213 	/* Check that no more one bits are present */
2214 	for ( ; i < 64; i++)
2215 		if (mask & (1LLU << i))
2216 			return -EINVAL;
2217 
2218 	/* Check that the input mask is a prefix or the right length. */
2219 	if (n_ones + n_trailing_zeros != mask_length)
2220 		return -EINVAL;
2221 
2222 	*prefix_length = n_ones;
2223 	return 0;
2224 }
2225 
2226 static int
2227 token_is_comment(const char *token)
2228 {
2229 	if ((token[0] == '#') ||
2230 	    (token[0] == ';') ||
2231 	    ((token[0] == '/') && (token[1] == '/')))
2232 		return 1; /* TRUE. */
2233 
2234 	return 0; /* FALSE. */
2235 }
2236 
2237 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2238 
2239 struct rte_swx_table_entry *
2240 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2241 				      const char *table_name,
2242 				      const char *string,
2243 				      int *is_blank_or_comment)
2244 {
2245 	char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2246 	struct table *table;
2247 	struct action *action;
2248 	struct rte_swx_table_entry *entry = NULL;
2249 	char *s0 = NULL, *s;
2250 	uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2251 	int lpm = 0, blank_or_comment = 0;
2252 
2253 	/* Check input arguments. */
2254 	if (!ctl)
2255 		goto error;
2256 
2257 	if (!table_name || !table_name[0])
2258 		goto error;
2259 
2260 	table = table_find(ctl, table_name);
2261 	if (!table)
2262 		goto error;
2263 
2264 	if (!string || !string[0])
2265 		goto error;
2266 
2267 	/* Memory allocation. */
2268 	s0 = strdup(string);
2269 	if (!s0)
2270 		goto error;
2271 
2272 	entry = table_entry_alloc(table);
2273 	if (!entry)
2274 		goto error;
2275 
2276 	/* Parse the string into tokens. */
2277 	for (s = s0; ; ) {
2278 		char *token;
2279 
2280 		token = strtok_r(s, " \f\n\r\t\v", &s);
2281 		if (!token || token_is_comment(token))
2282 			break;
2283 
2284 		if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2285 			goto error;
2286 
2287 		token_array[n_tokens] = token;
2288 		n_tokens++;
2289 	}
2290 
2291 	if (!n_tokens) {
2292 		blank_or_comment = 1;
2293 		goto error;
2294 	}
2295 
2296 	tokens = token_array;
2297 
2298 	/*
2299 	 * Match.
2300 	 */
2301 	if (!(n_tokens && !strcmp(tokens[0], "match")))
2302 		goto action;
2303 
2304 	if (n_tokens < 1 + table->info.n_match_fields)
2305 		goto error;
2306 
2307 	for (i = 0; i < table->info.n_match_fields; i++) {
2308 		struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2309 		char *mf_val = tokens[1 + i], *mf_mask = NULL;
2310 		uint64_t val, mask = UINT64_MAX;
2311 		uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2312 
2313 		/*
2314 		 * Mask.
2315 		 */
2316 		mf_mask = strchr(mf_val, '/');
2317 		if (mf_mask) {
2318 			*mf_mask = 0;
2319 			mf_mask++;
2320 
2321 			/* Parse. */
2322 			mask = strtoull(mf_mask, &mf_mask, 0);
2323 			if (mf_mask[0])
2324 				goto error;
2325 
2326 			/* LPM. */
2327 			if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2328 				int status;
2329 
2330 				lpm = 1;
2331 
2332 				lpm_prefix_length_max = mf->n_bits;
2333 
2334 				status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2335 				if (status)
2336 					goto error;
2337 			}
2338 
2339 			/* Endianness conversion. */
2340 			if (mf->is_header)
2341 				mask = field_hton(mask, mf->n_bits);
2342 		}
2343 
2344 		/* Copy to entry. */
2345 		if (entry->key_mask)
2346 			memcpy(&entry->key_mask[offset],
2347 			       (uint8_t *)&mask,
2348 			       mf->n_bits / 8);
2349 
2350 		/*
2351 		 * Value.
2352 		 */
2353 		/* Parse. */
2354 		val = strtoull(mf_val, &mf_val, 0);
2355 		if (mf_val[0])
2356 			goto error;
2357 
2358 		/* Endianness conversion. */
2359 		if (mf->is_header)
2360 			val = field_hton(val, mf->n_bits);
2361 
2362 		/* Copy to entry. */
2363 		memcpy(&entry->key[offset],
2364 		       (uint8_t *)&val,
2365 		       mf->n_bits / 8);
2366 	}
2367 
2368 	tokens += 1 + table->info.n_match_fields;
2369 	n_tokens -= 1 + table->info.n_match_fields;
2370 
2371 	/*
2372 	 * Match priority.
2373 	 */
2374 	if (n_tokens && !strcmp(tokens[0], "priority")) {
2375 		char *priority = tokens[1];
2376 		uint32_t val;
2377 
2378 		if (n_tokens < 2)
2379 			goto error;
2380 
2381 		/* Parse. */
2382 		val = strtoul(priority, &priority, 0);
2383 		if (priority[0])
2384 			goto error;
2385 
2386 		/* Copy to entry. */
2387 		entry->key_priority = val;
2388 
2389 		tokens += 2;
2390 		n_tokens -= 2;
2391 	}
2392 
2393 	/* LPM. */
2394 	if (lpm)
2395 		entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2396 
2397 	/*
2398 	 * Action.
2399 	 */
2400 action:
2401 	if (!(n_tokens && !strcmp(tokens[0], "action")))
2402 		goto other;
2403 
2404 	if (n_tokens < 2)
2405 		goto error;
2406 
2407 	action = action_find(ctl, tokens[1]);
2408 	if (!action)
2409 		goto error;
2410 
2411 	if (n_tokens < 2 + action->info.n_args * 2)
2412 		goto error;
2413 
2414 	/* action_id. */
2415 	entry->action_id = action - ctl->actions;
2416 
2417 	/* action_data. */
2418 	for (i = 0; i < action->info.n_args; i++) {
2419 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2420 		char *arg_name, *arg_val;
2421 		uint64_t val;
2422 
2423 		arg_name = tokens[2 + i * 2];
2424 		arg_val = tokens[2 + i * 2 + 1];
2425 
2426 		if (strcmp(arg_name, arg->name))
2427 			goto error;
2428 
2429 		val = strtoull(arg_val, &arg_val, 0);
2430 		if (arg_val[0])
2431 			goto error;
2432 
2433 		/* Endianness conversion. */
2434 		if (arg->is_network_byte_order)
2435 			val = field_hton(val, arg->n_bits);
2436 
2437 		/* Copy to entry. */
2438 		memcpy(&entry->action_data[arg_offset],
2439 		       (uint8_t *)&val,
2440 		       arg->n_bits / 8);
2441 
2442 		arg_offset += arg->n_bits / 8;
2443 	}
2444 
2445 	tokens += 2 + action->info.n_args * 2;
2446 	n_tokens -= 2 + action->info.n_args * 2;
2447 
2448 other:
2449 	if (n_tokens)
2450 		goto error;
2451 
2452 	free(s0);
2453 	return entry;
2454 
2455 error:
2456 	table_entry_free(entry);
2457 	free(s0);
2458 	if (is_blank_or_comment)
2459 		*is_blank_or_comment = blank_or_comment;
2460 	return NULL;
2461 }
2462 
2463 static void
2464 table_entry_printf(FILE *f,
2465 		   struct rte_swx_ctl_pipeline *ctl,
2466 		   struct table *table,
2467 		   struct rte_swx_table_entry *entry)
2468 {
2469 	struct action *action = &ctl->actions[entry->action_id];
2470 	uint32_t i;
2471 
2472 	fprintf(f, "match ");
2473 	for (i = 0; i < table->params.key_size; i++)
2474 		fprintf(f, "%02x", entry->key[i]);
2475 
2476 	if (entry->key_mask) {
2477 		fprintf(f, "/");
2478 		for (i = 0; i < table->params.key_size; i++)
2479 			fprintf(f, "%02x", entry->key_mask[i]);
2480 	}
2481 
2482 	fprintf(f, " priority %u", entry->key_priority);
2483 
2484 	fprintf(f, " action %s ", action->info.name);
2485 	for (i = 0; i < action->data_size; i++)
2486 		fprintf(f, "%02x", entry->action_data[i]);
2487 
2488 	fprintf(f, "\n");
2489 }
2490 
2491 int
2492 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2493 				   struct rte_swx_ctl_pipeline *ctl,
2494 				   const char *table_name)
2495 {
2496 	struct table *table;
2497 	struct rte_swx_table_entry *entry;
2498 	uint32_t n_entries = 0, i;
2499 
2500 	if (!f || !ctl || !table_name || !table_name[0])
2501 		return -EINVAL;
2502 
2503 	table = table_find(ctl, table_name);
2504 	if (!table)
2505 		return -EINVAL;
2506 
2507 	/* Table. */
2508 	fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2509 		table->info.name,
2510 		table->params.key_size,
2511 		table->params.key_offset);
2512 
2513 	for (i = 0; i < table->params.key_size; i++)
2514 		fprintf(f, "%02x", table->params.key_mask0[i]);
2515 
2516 	fprintf(f, "], action data size %u bytes\n",
2517 		table->params.action_data_size);
2518 
2519 	/* Table entries. */
2520 	TAILQ_FOREACH(entry, &table->entries, node) {
2521 		table_entry_printf(f, ctl, table, entry);
2522 		n_entries++;
2523 	}
2524 
2525 	TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2526 		table_entry_printf(f, ctl, table, entry);
2527 		n_entries++;
2528 	}
2529 
2530 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
2531 		table_entry_printf(f, ctl, table, entry);
2532 		n_entries++;
2533 	}
2534 
2535 	fprintf(f, "# Table %s currently has %u entries.\n",
2536 		table_name,
2537 		n_entries);
2538 	return 0;
2539 }
2540 
2541 int
2542 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
2543 				      struct rte_swx_ctl_pipeline *ctl,
2544 				      const char *selector_name)
2545 {
2546 	struct selector *s;
2547 	uint32_t group_id;
2548 
2549 	if (!f || !ctl || !selector_name || !selector_name[0])
2550 		return -EINVAL;
2551 
2552 	s = selector_find(ctl, selector_name);
2553 	if (!s)
2554 		return -EINVAL;
2555 
2556 	/* Selector. */
2557 	fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
2558 		s->info.name,
2559 		s->info.n_groups_max,
2560 		s->info.n_members_per_group_max);
2561 
2562 	/* Groups. */
2563 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2564 		struct rte_swx_table_selector_group *group = s->groups[group_id];
2565 		struct rte_swx_table_selector_member *m;
2566 		uint32_t n_members = 0;
2567 
2568 		fprintf(f, "Group %u = [", group_id);
2569 
2570 		/* Non-empty group. */
2571 		if (group)
2572 			TAILQ_FOREACH(m, &group->members, node) {
2573 				fprintf(f, "%u:%u ", m->member_id, m->member_weight);
2574 				n_members++;
2575 			}
2576 
2577 		/* Empty group. */
2578 		if (!n_members)
2579 			fprintf(f, "0:1 ");
2580 
2581 		fprintf(f, "]\n");
2582 	}
2583 
2584 	return 0;
2585 }
2586