xref: /dpdk/lib/pipeline/rte_swx_ctl.c (revision b7fe612ac1de393f869c9818d5503633c8e96b36)
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_ctl.h"
14 
15 #define CHECK(condition, err_code)                                             \
16 do {                                                                           \
17 	if (!(condition))                                                      \
18 		return -(err_code);                                            \
19 } while (0)
20 
21 #define ntoh64(x) rte_be_to_cpu_64(x)
22 #define hton64(x) rte_cpu_to_be_64(x)
23 
24 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
25 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
26 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
27 #else
28 #define field_ntoh(val, n_bits) (val)
29 #define field_hton(val, n_bits) (val)
30 #endif
31 
32 struct action {
33 	struct rte_swx_ctl_action_info info;
34 	struct rte_swx_ctl_action_arg_info *args;
35 	uint32_t data_size;
36 };
37 
38 struct table {
39 	struct rte_swx_ctl_table_info info;
40 	struct rte_swx_ctl_table_match_field_info *mf;
41 
42 	/* Match field with the smallest offset. */
43 	struct rte_swx_ctl_table_match_field_info *mf_first;
44 
45 	/* Match field with the biggest offset. */
46 	struct rte_swx_ctl_table_match_field_info *mf_last;
47 
48 	struct rte_swx_ctl_table_action_info *actions;
49 	struct rte_swx_table_ops ops;
50 	struct rte_swx_table_params params;
51 
52 	/* Set of "stable" keys: these keys are currently part of the table;
53 	 * these keys will be preserved with no action data changes after the
54 	 * next commit.
55 	 */
56 	struct rte_swx_table_entry_list entries;
57 
58 	/* Set of new keys: these keys are currently NOT part of the table;
59 	 * these keys will be added to the table on the next commit, if
60 	 * the commit operation is successful.
61 	 */
62 	struct rte_swx_table_entry_list pending_add;
63 
64 	/* Set of keys to be modified: these keys are currently part of the
65 	 * table; these keys are still going to be part of the table after the
66 	 * next commit, but their action data will be modified if the commit
67 	 * operation is successful. The modify0 list contains the keys with the
68 	 * current action data, the modify1 list contains the keys with the
69 	 * modified action data.
70 	 */
71 	struct rte_swx_table_entry_list pending_modify0;
72 	struct rte_swx_table_entry_list pending_modify1;
73 
74 	/* Set of keys to be deleted: these keys are currently part of the
75 	 * table; these keys are to be deleted from the table on the next
76 	 * commit, if the commit operation is successful.
77 	 */
78 	struct rte_swx_table_entry_list pending_delete;
79 
80 	/* The pending default action: this is NOT the current default action;
81 	 * this will be the new default action after the next commit, if the
82 	 * next commit operation is successful.
83 	 */
84 	struct rte_swx_table_entry *pending_default;
85 
86 	int is_stub;
87 	uint32_t n_add;
88 	uint32_t n_modify;
89 	uint32_t n_delete;
90 };
91 
92 struct rte_swx_ctl_pipeline {
93 	struct rte_swx_ctl_pipeline_info info;
94 	struct rte_swx_pipeline *p;
95 	struct action *actions;
96 	struct table *tables;
97 	struct rte_swx_table_state *ts;
98 	struct rte_swx_table_state *ts_next;
99 	int numa_node;
100 };
101 
102 static struct action *
103 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
104 {
105 	uint32_t i;
106 
107 	for (i = 0; i < ctl->info.n_actions; i++) {
108 		struct action *a = &ctl->actions[i];
109 
110 		if (!strcmp(action_name, a->info.name))
111 			return a;
112 	}
113 
114 	return NULL;
115 }
116 
117 static void
118 action_free(struct rte_swx_ctl_pipeline *ctl)
119 {
120 	uint32_t i;
121 
122 	if (!ctl->actions)
123 		return;
124 
125 	for (i = 0; i < ctl->info.n_actions; i++) {
126 		struct action *action = &ctl->actions[i];
127 
128 		free(action->args);
129 	}
130 
131 	free(ctl->actions);
132 	ctl->actions = NULL;
133 }
134 
135 static struct table *
136 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
137 {
138 	uint32_t i;
139 
140 	for (i = 0; i < ctl->info.n_tables; i++) {
141 		struct table *table = &ctl->tables[i];
142 
143 		if (!strcmp(table_name, table->info.name))
144 			return table;
145 	}
146 
147 	return NULL;
148 }
149 
150 static int
151 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
152 {
153 	struct table *table = &ctl->tables[table_id];
154 	struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
155 	uint8_t *key_mask = NULL;
156 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
157 	uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
158 
159 	if (table->info.n_match_fields) {
160 		uint32_t n_match_fields_em = 0, i;
161 
162 		/* Find first (smallest offset) and last (biggest offset) match fields. */
163 		first = &table->mf[0];
164 		last = &table->mf[0];
165 
166 		for (i = 1; i < table->info.n_match_fields; i++) {
167 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
168 
169 			if (f->offset < first->offset)
170 				first = f;
171 
172 			if (f->offset > last->offset)
173 				last = f;
174 		}
175 
176 		/* match_type. */
177 		for (i = 0; i < table->info.n_match_fields; i++) {
178 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
179 
180 			if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
181 				n_match_fields_em++;
182 		}
183 
184 		if (n_match_fields_em == table->info.n_match_fields)
185 			match_type = RTE_SWX_TABLE_MATCH_EXACT;
186 		else if ((n_match_fields_em == table->info.n_match_fields - 1) &&
187 			 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
188 			match_type = RTE_SWX_TABLE_MATCH_LPM;
189 
190 		/* key_offset. */
191 		key_offset = first->offset / 8;
192 
193 		/* key_size. */
194 		key_size = (last->offset + last->n_bits - first->offset) / 8;
195 
196 		/* key_mask. */
197 		key_mask = calloc(1, key_size);
198 		CHECK(key_mask, ENOMEM);
199 
200 		for (i = 0; i < table->info.n_match_fields; i++) {
201 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
202 			uint32_t start;
203 			size_t size;
204 
205 			start = (f->offset - first->offset) / 8;
206 			size = f->n_bits / 8;
207 
208 			memset(&key_mask[start], 0xFF, size);
209 		}
210 	}
211 
212 	/* action_data_size. */
213 	for (i = 0; i < table->info.n_actions; i++) {
214 		uint32_t action_id = table->actions[i].action_id;
215 		struct action *a = &ctl->actions[action_id];
216 
217 		if (a->data_size > action_data_size)
218 			action_data_size = a->data_size;
219 	}
220 
221 	/* Fill in. */
222 	table->params.match_type = match_type;
223 	table->params.key_size = key_size;
224 	table->params.key_offset = key_offset;
225 	table->params.key_mask0 = key_mask;
226 	table->params.action_data_size = action_data_size;
227 	table->params.n_keys_max = table->info.size;
228 
229 	table->mf_first = first;
230 	table->mf_last = last;
231 
232 	return 0;
233 }
234 
235 static void
236 table_entry_free(struct rte_swx_table_entry *entry)
237 {
238 	if (!entry)
239 		return;
240 
241 	free(entry->key);
242 	free(entry->key_mask);
243 	free(entry->action_data);
244 	free(entry);
245 }
246 
247 static struct rte_swx_table_entry *
248 table_entry_alloc(struct table *table)
249 {
250 	struct rte_swx_table_entry *entry;
251 
252 	entry = calloc(1, sizeof(struct rte_swx_table_entry));
253 	if (!entry)
254 		goto error;
255 
256 	/* key, key_mask. */
257 	if (!table->is_stub) {
258 		entry->key = calloc(1, table->params.key_size);
259 		if (!entry->key)
260 			goto error;
261 
262 		if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
263 			entry->key_mask = calloc(1, table->params.key_size);
264 			if (!entry->key_mask)
265 				goto error;
266 		}
267 	}
268 
269 	/* action_data. */
270 	if (table->params.action_data_size) {
271 		entry->action_data = calloc(1, table->params.action_data_size);
272 		if (!entry->action_data)
273 			goto error;
274 	}
275 
276 	return entry;
277 
278 error:
279 	table_entry_free(entry);
280 	return NULL;
281 }
282 
283 static int
284 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
285 {
286 	uint8_t *key_mask0 = table->params.key_mask0;
287 	uint32_t key_size = table->params.key_size, i;
288 
289 	if (!entry->key_mask)
290 		return 0;
291 
292 	for (i = 0; i < key_size; i++) {
293 		uint8_t km0 = key_mask0[i];
294 		uint8_t km = entry->key_mask[i];
295 
296 		if ((km & km0) != km0)
297 			return -EINVAL;
298 	}
299 
300 	return 0;
301 }
302 
303 static int
304 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
305 		  uint32_t table_id,
306 		  struct rte_swx_table_entry *entry,
307 		  int key_check,
308 		  int data_check)
309 {
310 	struct table *table = &ctl->tables[table_id];
311 	int status;
312 
313 	CHECK(entry, EINVAL);
314 
315 	if (key_check) {
316 		if (table->is_stub) {
317 			/* key. */
318 			CHECK(!entry->key, EINVAL);
319 
320 			/* key_mask. */
321 			CHECK(!entry->key_mask, EINVAL);
322 		} else {
323 			/* key. */
324 			CHECK(entry->key, EINVAL);
325 
326 			/* key_mask. */
327 			switch (table->params.match_type) {
328 			case RTE_SWX_TABLE_MATCH_WILDCARD:
329 				break;
330 
331 			case RTE_SWX_TABLE_MATCH_LPM:
332 				/* TBD Check that key mask is prefix. */
333 				break;
334 
335 			case RTE_SWX_TABLE_MATCH_EXACT:
336 				status = table_entry_key_check_em(table, entry);
337 				if (status)
338 					return status;
339 				break;
340 
341 			default:
342 				CHECK(0, EINVAL);
343 			}
344 		}
345 	}
346 
347 	if (data_check) {
348 		struct action *a;
349 		uint32_t i;
350 
351 		/* action_id. */
352 		for (i = 0; i < table->info.n_actions; i++)
353 			if (entry->action_id == table->actions[i].action_id)
354 				break;
355 
356 		CHECK(i < table->info.n_actions, EINVAL);
357 
358 		/* action_data. */
359 		a = &ctl->actions[entry->action_id];
360 		CHECK(!(a->data_size && !entry->action_data), EINVAL);
361 	}
362 
363 	return 0;
364 }
365 
366 static struct rte_swx_table_entry *
367 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
368 		      uint32_t table_id,
369 		      struct rte_swx_table_entry *entry,
370 		      int key_duplicate,
371 		      int data_duplicate)
372 {
373 	struct table *table = &ctl->tables[table_id];
374 	struct rte_swx_table_entry *new_entry = NULL;
375 
376 	if (!entry)
377 		goto error;
378 
379 	new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
380 	if (!new_entry)
381 		goto error;
382 
383 	if (key_duplicate && !table->is_stub) {
384 		/* key. */
385 		if (!entry->key)
386 			goto error;
387 
388 		new_entry->key = malloc(table->params.key_size);
389 		if (!new_entry->key)
390 			goto error;
391 
392 		memcpy(new_entry->key, entry->key, table->params.key_size);
393 
394 		/* key_signature. */
395 		new_entry->key_signature = entry->key_signature;
396 
397 		/* key_mask. */
398 		if (entry->key_mask) {
399 			new_entry->key_mask = malloc(table->params.key_size);
400 			if (!new_entry->key_mask)
401 				goto error;
402 
403 			memcpy(new_entry->key_mask,
404 			       entry->key_mask,
405 			       table->params.key_size);
406 		}
407 
408 		/* key_priority. */
409 		new_entry->key_priority = entry->key_priority;
410 	}
411 
412 	if (data_duplicate) {
413 		struct action *a;
414 		uint32_t i;
415 
416 		/* action_id. */
417 		for (i = 0; i < table->info.n_actions; i++)
418 			if (entry->action_id == table->actions[i].action_id)
419 				break;
420 
421 		if (i >= table->info.n_actions)
422 			goto error;
423 
424 		new_entry->action_id = entry->action_id;
425 
426 		/* action_data. */
427 		a = &ctl->actions[entry->action_id];
428 		if (a->data_size && !entry->action_data)
429 			goto error;
430 
431 		/* The table layer provisions a constant action data size per
432 		 * entry, which should be the largest data size for all the
433 		 * actions enabled for the current table, and attempts to copy
434 		 * this many bytes each time a table entry is added, even if the
435 		 * specific action requires less data or even no data at all,
436 		 * hence we always have to allocate the max.
437 		 */
438 		new_entry->action_data = calloc(1, table->params.action_data_size);
439 		if (!new_entry->action_data)
440 			goto error;
441 
442 		if (a->data_size)
443 			memcpy(new_entry->action_data,
444 			       entry->action_data,
445 			       a->data_size);
446 	}
447 
448 	return new_entry;
449 
450 error:
451 	table_entry_free(new_entry);
452 	return NULL;
453 }
454 
455 static int
456 table_entry_keycmp(struct table *table,
457 		   struct rte_swx_table_entry *e0,
458 		   struct rte_swx_table_entry *e1)
459 {
460 	uint32_t key_size = table->params.key_size;
461 	uint32_t i;
462 
463 	for (i = 0; i < key_size; i++) {
464 		uint8_t *key_mask0 = table->params.key_mask0;
465 		uint8_t km0, km[2], k[2];
466 
467 		km0 = key_mask0 ? key_mask0[i] : 0xFF;
468 
469 		km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
470 		km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
471 
472 		k[0] = e0->key[i];
473 		k[1] = e1->key[i];
474 
475 		/* Mask comparison. */
476 		if ((km[0] & km0) != (km[1] & km0))
477 			return 1; /* Not equal. */
478 
479 		/* Value comparison. */
480 		if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
481 			return 1; /* Not equal. */
482 	}
483 
484 	return 0; /* Equal. */
485 }
486 
487 static struct rte_swx_table_entry *
488 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
489 {
490 	struct rte_swx_table_entry *e;
491 
492 	TAILQ_FOREACH(e, &table->entries, node)
493 		if (!table_entry_keycmp(table, entry, e))
494 			return e; /* Found. */
495 
496 	return NULL; /* Not found. */
497 }
498 
499 static void
500 table_entries_free(struct table *table)
501 {
502 	for ( ; ; ) {
503 		struct rte_swx_table_entry *entry;
504 
505 		entry = TAILQ_FIRST(&table->entries);
506 		if (!entry)
507 			break;
508 
509 		TAILQ_REMOVE(&table->entries, entry, node);
510 		table_entry_free(entry);
511 	}
512 }
513 
514 static struct rte_swx_table_entry *
515 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
516 {
517 	struct rte_swx_table_entry *e;
518 
519 	TAILQ_FOREACH(e, &table->pending_add, node)
520 		if (!table_entry_keycmp(table, entry, e))
521 			return e; /* Found. */
522 
523 	return NULL; /* Not found. */
524 }
525 
526 static void
527 table_pending_add_admit(struct table *table)
528 {
529 	TAILQ_CONCAT(&table->entries, &table->pending_add, node);
530 }
531 
532 static void
533 table_pending_add_free(struct table *table)
534 {
535 	for ( ; ; ) {
536 		struct rte_swx_table_entry *entry;
537 
538 		entry = TAILQ_FIRST(&table->pending_add);
539 		if (!entry)
540 			break;
541 
542 		TAILQ_REMOVE(&table->pending_add, entry, node);
543 		table_entry_free(entry);
544 	}
545 }
546 
547 static struct rte_swx_table_entry *
548 table_pending_modify0_find(struct table *table,
549 			   struct rte_swx_table_entry *entry)
550 {
551 	struct rte_swx_table_entry *e;
552 
553 	TAILQ_FOREACH(e, &table->pending_modify0, node)
554 		if (!table_entry_keycmp(table, entry, e))
555 			return e; /* Found. */
556 
557 	return NULL; /* Not found. */
558 }
559 
560 static void
561 table_pending_modify0_admit(struct table *table)
562 {
563 	TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
564 }
565 
566 static void
567 table_pending_modify0_free(struct table *table)
568 {
569 	for ( ; ; ) {
570 		struct rte_swx_table_entry *entry;
571 
572 		entry = TAILQ_FIRST(&table->pending_modify0);
573 		if (!entry)
574 			break;
575 
576 		TAILQ_REMOVE(&table->pending_modify0, entry, node);
577 		table_entry_free(entry);
578 	}
579 }
580 
581 static struct rte_swx_table_entry *
582 table_pending_modify1_find(struct table *table,
583 			   struct rte_swx_table_entry *entry)
584 {
585 	struct rte_swx_table_entry *e;
586 
587 	TAILQ_FOREACH(e, &table->pending_modify1, node)
588 		if (!table_entry_keycmp(table, entry, e))
589 			return e; /* Found. */
590 
591 	return NULL; /* Not found. */
592 }
593 
594 static void
595 table_pending_modify1_admit(struct table *table)
596 {
597 	TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
598 }
599 
600 static void
601 table_pending_modify1_free(struct table *table)
602 {
603 	for ( ; ; ) {
604 		struct rte_swx_table_entry *entry;
605 
606 		entry = TAILQ_FIRST(&table->pending_modify1);
607 		if (!entry)
608 			break;
609 
610 		TAILQ_REMOVE(&table->pending_modify1, entry, node);
611 		table_entry_free(entry);
612 	}
613 }
614 
615 static struct rte_swx_table_entry *
616 table_pending_delete_find(struct table *table,
617 			  struct rte_swx_table_entry *entry)
618 {
619 	struct rte_swx_table_entry *e;
620 
621 	TAILQ_FOREACH(e, &table->pending_delete, node)
622 		if (!table_entry_keycmp(table, entry, e))
623 			return e; /* Found. */
624 
625 	return NULL; /* Not found. */
626 }
627 
628 static void
629 table_pending_delete_admit(struct table *table)
630 {
631 	TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
632 }
633 
634 static void
635 table_pending_delete_free(struct table *table)
636 {
637 	for ( ; ; ) {
638 		struct rte_swx_table_entry *entry;
639 
640 		entry = TAILQ_FIRST(&table->pending_delete);
641 		if (!entry)
642 			break;
643 
644 		TAILQ_REMOVE(&table->pending_delete, entry, node);
645 		table_entry_free(entry);
646 	}
647 }
648 
649 static void
650 table_pending_default_free(struct table *table)
651 {
652 	if (!table->pending_default)
653 		return;
654 
655 	free(table->pending_default->action_data);
656 	free(table->pending_default);
657 	table->pending_default = NULL;
658 }
659 
660 static int
661 table_is_update_pending(struct table *table, int consider_pending_default)
662 {
663 	struct rte_swx_table_entry *e;
664 	uint32_t n = 0;
665 
666 	/* Pending add. */
667 	TAILQ_FOREACH(e, &table->pending_add, node)
668 		n++;
669 
670 	/* Pending modify. */
671 	TAILQ_FOREACH(e, &table->pending_modify1, node)
672 		n++;
673 
674 	/* Pending delete. */
675 	TAILQ_FOREACH(e, &table->pending_delete, node)
676 		n++;
677 
678 	/* Pending default. */
679 	if (consider_pending_default && table->pending_default)
680 		n++;
681 
682 	return n;
683 }
684 
685 static void
686 table_free(struct rte_swx_ctl_pipeline *ctl)
687 {
688 	uint32_t i;
689 
690 	if (!ctl->tables)
691 		return;
692 
693 	for (i = 0; i < ctl->info.n_tables; i++) {
694 		struct table *table = &ctl->tables[i];
695 
696 		free(table->mf);
697 		free(table->actions);
698 		free(table->params.key_mask0);
699 
700 		table_entries_free(table);
701 		table_pending_add_free(table);
702 		table_pending_modify0_free(table);
703 		table_pending_modify1_free(table);
704 		table_pending_delete_free(table);
705 		table_pending_default_free(table);
706 	}
707 
708 	free(ctl->tables);
709 	ctl->tables = NULL;
710 }
711 
712 static void
713 table_state_free(struct rte_swx_ctl_pipeline *ctl)
714 {
715 	uint32_t i;
716 
717 	if (!ctl->ts_next)
718 		return;
719 
720 	/* For each table, free its table state. */
721 	for (i = 0; i < ctl->info.n_tables; i++) {
722 		struct table *table = &ctl->tables[i];
723 		struct rte_swx_table_state *ts = &ctl->ts_next[i];
724 
725 		/* Default action data. */
726 		free(ts->default_action_data);
727 
728 		/* Table object. */
729 		if (!table->is_stub && table->ops.free && ts->obj)
730 			table->ops.free(ts->obj);
731 	}
732 
733 	free(ctl->ts_next);
734 	ctl->ts_next = NULL;
735 }
736 
737 static int
738 table_state_create(struct rte_swx_ctl_pipeline *ctl)
739 {
740 	int status = 0;
741 	uint32_t i;
742 
743 	ctl->ts_next = calloc(ctl->info.n_tables,
744 			      sizeof(struct rte_swx_table_state));
745 	if (!ctl->ts_next) {
746 		status = -ENOMEM;
747 		goto error;
748 	}
749 
750 	for (i = 0; i < ctl->info.n_tables; i++) {
751 		struct table *table = &ctl->tables[i];
752 		struct rte_swx_table_state *ts = &ctl->ts[i];
753 		struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
754 
755 		/* Table object. */
756 		if (!table->is_stub && table->ops.add) {
757 			ts_next->obj = table->ops.create(&table->params,
758 							 &table->entries,
759 							 table->info.args,
760 							 ctl->numa_node);
761 			if (!ts_next->obj) {
762 				status = -ENODEV;
763 				goto error;
764 			}
765 		}
766 
767 		if (!table->is_stub && !table->ops.add)
768 			ts_next->obj = ts->obj;
769 
770 		/* Default action data: duplicate from current table state. */
771 		ts_next->default_action_data =
772 			malloc(table->params.action_data_size);
773 		if (!ts_next->default_action_data) {
774 			status = -ENOMEM;
775 			goto error;
776 		}
777 
778 		memcpy(ts_next->default_action_data,
779 		       ts->default_action_data,
780 		       table->params.action_data_size);
781 
782 		ts_next->default_action_id = ts->default_action_id;
783 	}
784 
785 	return 0;
786 
787 error:
788 	table_state_free(ctl);
789 	return status;
790 }
791 
792 void
793 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
794 {
795 	if (!ctl)
796 		return;
797 
798 	action_free(ctl);
799 
800 	table_state_free(ctl);
801 
802 	table_free(ctl);
803 
804 	free(ctl);
805 }
806 
807 struct rte_swx_ctl_pipeline *
808 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
809 {
810 	struct rte_swx_ctl_pipeline *ctl = NULL;
811 	uint32_t i;
812 	int status;
813 
814 	if (!p)
815 		goto error;
816 
817 	ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
818 	if (!ctl)
819 		goto error;
820 
821 	/* info. */
822 	status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
823 	if (status)
824 		goto error;
825 
826 	/* numa_node. */
827 	status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
828 	if (status)
829 		goto error;
830 
831 	/* p. */
832 	ctl->p = p;
833 
834 	/* actions. */
835 	ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
836 	if (!ctl->actions)
837 		goto error;
838 
839 	for (i = 0; i < ctl->info.n_actions; i++) {
840 		struct action *a = &ctl->actions[i];
841 		uint32_t j;
842 
843 		/* info. */
844 		status = rte_swx_ctl_action_info_get(p, i, &a->info);
845 		if (status)
846 			goto error;
847 
848 		/* args. */
849 		a->args = calloc(a->info.n_args,
850 				 sizeof(struct rte_swx_ctl_action_arg_info));
851 		if (!a->args)
852 			goto error;
853 
854 		for (j = 0; j < a->info.n_args; j++) {
855 			status = rte_swx_ctl_action_arg_info_get(p,
856 								 i,
857 								 j,
858 								 &a->args[j]);
859 			if (status)
860 				goto error;
861 		}
862 
863 		/* data_size. */
864 		for (j = 0; j < a->info.n_args; j++) {
865 			struct rte_swx_ctl_action_arg_info *info = &a->args[j];
866 
867 			a->data_size += info->n_bits;
868 		}
869 
870 		a->data_size = (a->data_size + 7) / 8;
871 	}
872 
873 	/* tables. */
874 	ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
875 	if (!ctl->tables)
876 		goto error;
877 
878 	for (i = 0; i < ctl->info.n_tables; i++) {
879 		struct table *t = &ctl->tables[i];
880 
881 		TAILQ_INIT(&t->entries);
882 		TAILQ_INIT(&t->pending_add);
883 		TAILQ_INIT(&t->pending_modify0);
884 		TAILQ_INIT(&t->pending_modify1);
885 		TAILQ_INIT(&t->pending_delete);
886 	}
887 
888 	for (i = 0; i < ctl->info.n_tables; i++) {
889 		struct table *t = &ctl->tables[i];
890 		uint32_t j;
891 
892 		/* info. */
893 		status = rte_swx_ctl_table_info_get(p, i, &t->info);
894 		if (status)
895 			goto error;
896 
897 		/* mf. */
898 		t->mf = calloc(t->info.n_match_fields,
899 			sizeof(struct rte_swx_ctl_table_match_field_info));
900 		if (!t->mf)
901 			goto error;
902 
903 		for (j = 0; j < t->info.n_match_fields; j++) {
904 			status = rte_swx_ctl_table_match_field_info_get(p,
905 				i,
906 				j,
907 				&t->mf[j]);
908 			if (status)
909 				goto error;
910 		}
911 
912 		/* actions. */
913 		t->actions = calloc(t->info.n_actions,
914 			sizeof(struct rte_swx_ctl_table_action_info));
915 		if (!t->actions)
916 			goto error;
917 
918 		for (j = 0; j < t->info.n_actions; j++) {
919 			status = rte_swx_ctl_table_action_info_get(p,
920 				i,
921 				j,
922 				&t->actions[j]);
923 			if (status ||
924 			    t->actions[j].action_id >= ctl->info.n_actions)
925 				goto error;
926 		}
927 
928 		/* ops, is_stub. */
929 		status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
930 		if (status)
931 			goto error;
932 
933 		if ((t->is_stub && t->info.n_match_fields) ||
934 		    (!t->is_stub && !t->info.n_match_fields))
935 			goto error;
936 
937 		/* params. */
938 		status = table_params_get(ctl, i);
939 		if (status)
940 			goto error;
941 	}
942 
943 	/* ts. */
944 	status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
945 	if (status)
946 		goto error;
947 
948 	/* ts_next. */
949 	status = table_state_create(ctl);
950 	if (status)
951 		goto error;
952 
953 	return ctl;
954 
955 error:
956 	rte_swx_ctl_pipeline_free(ctl);
957 	return NULL;
958 }
959 
960 int
961 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
962 				     const char *table_name,
963 				     struct rte_swx_table_entry *entry)
964 {
965 	struct table *table;
966 	struct rte_swx_table_entry *new_entry, *existing_entry;
967 	uint32_t table_id;
968 
969 	CHECK(ctl, EINVAL);
970 	CHECK(table_name && table_name[0], EINVAL);
971 
972 	table = table_find(ctl, table_name);
973 	CHECK(table, EINVAL);
974 	table_id = table - ctl->tables;
975 
976 	CHECK(entry, EINVAL);
977 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
978 
979 	new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
980 	CHECK(new_entry, ENOMEM);
981 
982 	/* The new entry is found in the table->entries list:
983 	 * - Add the new entry to the table->pending_modify1 list;
984 	 * - Move the existing entry from the table->entries list to the
985 	 *   table->pending_modify0 list.
986 	 */
987 	existing_entry = table_entries_find(table, entry);
988 	if (existing_entry) {
989 		TAILQ_INSERT_TAIL(&table->pending_modify1,
990 				  new_entry,
991 				  node);
992 
993 		TAILQ_REMOVE(&table->entries,
994 			     existing_entry,
995 			     node);
996 
997 		TAILQ_INSERT_TAIL(&table->pending_modify0,
998 				  existing_entry,
999 				  node);
1000 
1001 		return 0;
1002 	}
1003 
1004 	/* The new entry is found in the table->pending_add list:
1005 	 * - Replace the entry in the table->pending_add list with the new entry
1006 	 *   (and free the replaced entry).
1007 	 */
1008 	existing_entry = table_pending_add_find(table, entry);
1009 	if (existing_entry) {
1010 		TAILQ_INSERT_AFTER(&table->pending_add,
1011 				   existing_entry,
1012 				   new_entry,
1013 				   node);
1014 
1015 		TAILQ_REMOVE(&table->pending_add,
1016 			     existing_entry,
1017 			     node);
1018 
1019 		table_entry_free(existing_entry);
1020 
1021 		return 0;
1022 	}
1023 
1024 	/* The new entry is found in the table->pending_modify1 list:
1025 	 * - Replace the entry in the table->pending_modify1 list with the new
1026 	 *   entry (and free the replaced entry).
1027 	 */
1028 	existing_entry = table_pending_modify1_find(table, entry);
1029 	if (existing_entry) {
1030 		TAILQ_INSERT_AFTER(&table->pending_modify1,
1031 				   existing_entry,
1032 				   new_entry,
1033 				   node);
1034 
1035 		TAILQ_REMOVE(&table->pending_modify1,
1036 			     existing_entry,
1037 			     node);
1038 
1039 		table_entry_free(existing_entry);
1040 
1041 		return 0;
1042 	}
1043 
1044 	/* The new entry is found in the table->pending_delete list:
1045 	 * - Add the new entry to the table->pending_modify1 list;
1046 	 * - Move the existing entry from the table->pending_delete list to the
1047 	 *   table->pending_modify0 list.
1048 	 */
1049 	existing_entry = table_pending_delete_find(table, entry);
1050 	if (existing_entry) {
1051 		TAILQ_INSERT_TAIL(&table->pending_modify1,
1052 				  new_entry,
1053 				  node);
1054 
1055 		TAILQ_REMOVE(&table->pending_delete,
1056 			     existing_entry,
1057 			     node);
1058 
1059 		TAILQ_INSERT_TAIL(&table->pending_modify0,
1060 				  existing_entry,
1061 				  node);
1062 
1063 		return 0;
1064 	}
1065 
1066 	/* The new entry is not found in any of the above lists:
1067 	 * - Add the new entry to the table->pending_add list.
1068 	 */
1069 	TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1070 
1071 	return 0;
1072 }
1073 
1074 int
1075 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1076 					const char *table_name,
1077 					struct rte_swx_table_entry *entry)
1078 {
1079 	struct table *table;
1080 	struct rte_swx_table_entry *existing_entry;
1081 	uint32_t table_id;
1082 
1083 	CHECK(ctl, EINVAL);
1084 
1085 	CHECK(table_name && table_name[0], EINVAL);
1086 	table = table_find(ctl, table_name);
1087 	CHECK(table, EINVAL);
1088 	table_id = table - ctl->tables;
1089 
1090 	CHECK(entry, EINVAL);
1091 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1092 
1093 	/* The entry is found in the table->entries list:
1094 	 * - Move the existing entry from the table->entries list to to the
1095 	 *   table->pending_delete list.
1096 	 */
1097 	existing_entry = table_entries_find(table, entry);
1098 	if (existing_entry) {
1099 		TAILQ_REMOVE(&table->entries,
1100 			     existing_entry,
1101 			     node);
1102 
1103 		TAILQ_INSERT_TAIL(&table->pending_delete,
1104 				  existing_entry,
1105 				  node);
1106 
1107 		return 0;
1108 	}
1109 
1110 	/* The entry is found in the table->pending_add list:
1111 	 * - Remove the entry from the table->pending_add list and free it.
1112 	 */
1113 	existing_entry = table_pending_add_find(table, entry);
1114 	if (existing_entry) {
1115 		TAILQ_REMOVE(&table->pending_add,
1116 			     existing_entry,
1117 			     node);
1118 
1119 		table_entry_free(existing_entry);
1120 	}
1121 
1122 	/* The entry is found in the table->pending_modify1 list:
1123 	 * - Free the entry in the table->pending_modify1 list;
1124 	 * - Move the existing entry from the table->pending_modify0 list to the
1125 	 *   table->pending_delete list.
1126 	 */
1127 	existing_entry = table_pending_modify1_find(table, entry);
1128 	if (existing_entry) {
1129 		struct rte_swx_table_entry *real_existing_entry;
1130 
1131 		TAILQ_REMOVE(&table->pending_modify1,
1132 			     existing_entry,
1133 			     node);
1134 
1135 		table_entry_free(existing_entry);
1136 
1137 		real_existing_entry = table_pending_modify0_find(table, entry);
1138 		CHECK(real_existing_entry, EINVAL); /* Coverity. */
1139 
1140 		TAILQ_REMOVE(&table->pending_modify0,
1141 			     real_existing_entry,
1142 			     node);
1143 
1144 		TAILQ_INSERT_TAIL(&table->pending_delete,
1145 				  real_existing_entry,
1146 				  node);
1147 
1148 		return 0;
1149 	}
1150 
1151 	/* The entry is found in the table->pending_delete list:
1152 	 * - Do nothing: the existing entry is already in the
1153 	 *   table->pending_delete list, i.e. already marked for delete, so
1154 	 *   simply keep it there as it is.
1155 	 */
1156 
1157 	/* The entry is not found in any of the above lists:
1158 	 * - Do nothing: no existing entry to delete.
1159 	 */
1160 
1161 	return 0;
1162 }
1163 
1164 int
1165 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1166 					     const char *table_name,
1167 					     struct rte_swx_table_entry *entry)
1168 {
1169 	struct table *table;
1170 	struct rte_swx_table_entry *new_entry;
1171 	uint32_t table_id;
1172 
1173 	CHECK(ctl, EINVAL);
1174 
1175 	CHECK(table_name && table_name[0], EINVAL);
1176 	table = table_find(ctl, table_name);
1177 	CHECK(table, EINVAL);
1178 	table_id = table - ctl->tables;
1179 	CHECK(!table->info.default_action_is_const, EINVAL);
1180 
1181 	CHECK(entry, EINVAL);
1182 	CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1183 
1184 	new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1185 	CHECK(new_entry, ENOMEM);
1186 
1187 	table_pending_default_free(table);
1188 
1189 	table->pending_default = new_entry;
1190 	return 0;
1191 }
1192 
1193 
1194 static void
1195 table_entry_list_free(struct rte_swx_table_entry_list *list)
1196 {
1197 	for ( ; ; ) {
1198 		struct rte_swx_table_entry *entry;
1199 
1200 		entry = TAILQ_FIRST(list);
1201 		if (!entry)
1202 			break;
1203 
1204 		TAILQ_REMOVE(list, entry, node);
1205 		table_entry_free(entry);
1206 	}
1207 }
1208 
1209 static int
1210 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1211 			   uint32_t table_id,
1212 			   struct rte_swx_table_entry_list *dst,
1213 			   struct rte_swx_table_entry_list *src)
1214 {
1215 	struct rte_swx_table_entry *src_entry;
1216 
1217 	TAILQ_FOREACH(src_entry, src, node) {
1218 		struct rte_swx_table_entry *dst_entry;
1219 
1220 		dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1221 		if (!dst_entry)
1222 			goto error;
1223 
1224 		TAILQ_INSERT_TAIL(dst, dst_entry, node);
1225 	}
1226 
1227 	return 0;
1228 
1229 error:
1230 	table_entry_list_free(dst);
1231 	return -ENOMEM;
1232 }
1233 
1234 /* This commit stage contains all the operations that can fail; in case ANY of
1235  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1236  */
1237 static int
1238 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1239 	       uint32_t table_id,
1240 	       uint32_t after_swap)
1241 {
1242 	struct table *table = &ctl->tables[table_id];
1243 	struct rte_swx_table_state *ts = &ctl->ts[table_id];
1244 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1245 
1246 	if (table->is_stub || !table_is_update_pending(table, 0))
1247 		return 0;
1248 
1249 	/*
1250 	 * Current table supports incremental update.
1251 	 */
1252 	if (table->ops.add) {
1253 		/* Reset counters. */
1254 		table->n_add = 0;
1255 		table->n_modify = 0;
1256 		table->n_delete = 0;
1257 
1258 		/* Add pending rules. */
1259 		struct rte_swx_table_entry *entry;
1260 
1261 		TAILQ_FOREACH(entry, &table->pending_add, node) {
1262 			int status;
1263 
1264 			status = table->ops.add(ts_next->obj, entry);
1265 			if (status)
1266 				return status;
1267 
1268 			table->n_add++;
1269 		}
1270 
1271 		/* Modify pending rules. */
1272 		TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1273 			int status;
1274 
1275 			status = table->ops.add(ts_next->obj, entry);
1276 			if (status)
1277 				return status;
1278 
1279 			table->n_modify++;
1280 		}
1281 
1282 		/* Delete pending rules. */
1283 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
1284 			int status;
1285 
1286 			status = table->ops.del(ts_next->obj, entry);
1287 			if (status)
1288 				return status;
1289 
1290 			table->n_delete++;
1291 		}
1292 
1293 		return 0;
1294 	}
1295 
1296 	/*
1297 	 * Current table does NOT support incremental update.
1298 	 */
1299 	if (!after_swap) {
1300 		struct rte_swx_table_entry_list list;
1301 		int status;
1302 
1303 		/* Create updated list of entries included. */
1304 		TAILQ_INIT(&list);
1305 
1306 		status = table_entry_list_duplicate(ctl,
1307 						    table_id,
1308 						    &list,
1309 						    &table->entries);
1310 		if (status)
1311 			goto error;
1312 
1313 		status = table_entry_list_duplicate(ctl,
1314 						    table_id,
1315 						    &list,
1316 						    &table->pending_add);
1317 		if (status)
1318 			goto error;
1319 
1320 		status = table_entry_list_duplicate(ctl,
1321 						    table_id,
1322 						    &list,
1323 						    &table->pending_modify1);
1324 		if (status)
1325 			goto error;
1326 
1327 		/* Create new table object with the updates included. */
1328 		ts_next->obj = table->ops.create(&table->params,
1329 						 &list,
1330 						 table->info.args,
1331 						 ctl->numa_node);
1332 		if (!ts_next->obj) {
1333 			status = -ENODEV;
1334 			goto error;
1335 		}
1336 
1337 		table_entry_list_free(&list);
1338 
1339 		return 0;
1340 
1341 error:
1342 		table_entry_list_free(&list);
1343 		return status;
1344 	}
1345 
1346 	/* Free the old table object. */
1347 	if (ts_next->obj && table->ops.free)
1348 		table->ops.free(ts_next->obj);
1349 
1350 	/* Copy over the new table object. */
1351 	ts_next->obj = ts->obj;
1352 
1353 	return 0;
1354 }
1355 
1356 /* This commit stage contains all the operations that cannot fail. They are
1357  * executed only if the previous stage was successful for ALL the tables. Hence,
1358  * none of these operations has to be rolled back for ANY table.
1359  */
1360 static void
1361 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1362 {
1363 	struct table *table = &ctl->tables[table_id];
1364 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1365 	struct action *a;
1366 	uint8_t *action_data;
1367 	uint64_t action_id;
1368 
1369 	/* Copy the pending default entry. */
1370 	if (!table->pending_default)
1371 		return;
1372 
1373 	action_id = table->pending_default->action_id;
1374 	action_data = table->pending_default->action_data;
1375 	a = &ctl->actions[action_id];
1376 
1377 	memcpy(ts_next->default_action_data,
1378 	       action_data,
1379 	       a->data_size);
1380 
1381 	ts_next->default_action_id = action_id;
1382 }
1383 
1384 /* This last commit stage is simply finalizing a successful commit operation.
1385  * This stage is only executed if all the previous stages were successful. This
1386  * stage cannot fail.
1387  */
1388 static void
1389 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1390 {
1391 	struct table *table = &ctl->tables[table_id];
1392 
1393 	/* Move all the pending add entries to the table, as they are now part
1394 	 * of the table.
1395 	 */
1396 	table_pending_add_admit(table);
1397 
1398 	/* Move all the pending modify1 entries to table, are they are now part
1399 	 * of the table. Free up all the pending modify0 entries, as they are no
1400 	 * longer part of the table.
1401 	 */
1402 	table_pending_modify1_admit(table);
1403 	table_pending_modify0_free(table);
1404 
1405 	/* Free up all the pending delete entries, as they are no longer part of
1406 	 * the table.
1407 	 */
1408 	table_pending_delete_free(table);
1409 
1410 	/* Free up the pending default entry, as it is now part of the table. */
1411 	table_pending_default_free(table);
1412 }
1413 
1414 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1415  * commit operations that can fail did fail for ANY table. It reverts ALL the
1416  * tables to their state before the commit started, as if the commit never
1417  * happened.
1418  */
1419 static void
1420 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1421 {
1422 	struct table *table = &ctl->tables[table_id];
1423 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1424 
1425 	if (table->is_stub || !table_is_update_pending(table, 0))
1426 		return;
1427 
1428 	if (table->ops.add) {
1429 		struct rte_swx_table_entry *entry;
1430 
1431 		/* Add back all the entries that were just deleted. */
1432 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
1433 			if (!table->n_delete)
1434 				break;
1435 
1436 			table->ops.add(ts_next->obj, entry);
1437 			table->n_delete--;
1438 		}
1439 
1440 		/* Add back the old copy for all the entries that were just
1441 		 * modified.
1442 		 */
1443 		TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1444 			if (!table->n_modify)
1445 				break;
1446 
1447 			table->ops.add(ts_next->obj, entry);
1448 			table->n_modify--;
1449 		}
1450 
1451 		/* Delete all the entries that were just added. */
1452 		TAILQ_FOREACH(entry, &table->pending_add, node) {
1453 			if (!table->n_add)
1454 				break;
1455 
1456 			table->ops.del(ts_next->obj, entry);
1457 			table->n_add--;
1458 		}
1459 	} else {
1460 		struct rte_swx_table_state *ts = &ctl->ts[table_id];
1461 
1462 		/* Free the new table object, as update was cancelled. */
1463 		if (ts_next->obj && table->ops.free)
1464 			table->ops.free(ts_next->obj);
1465 
1466 		/* Reinstate the old table object. */
1467 		ts_next->obj = ts->obj;
1468 	}
1469 }
1470 
1471 /* This stage is conditionally executed (as instructed by the user) after a
1472  * failed commit operation to remove ALL the pending work for ALL the tables.
1473  */
1474 static void
1475 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1476 {
1477 	struct table *table = &ctl->tables[table_id];
1478 
1479 	/* Free up all the pending add entries, as none of them is part of the
1480 	 * table.
1481 	 */
1482 	table_pending_add_free(table);
1483 
1484 	/* Free up all the pending modify1 entries, as none of them made it to
1485 	 * the table. Add back all the pending modify0 entries, as none of them
1486 	 * was deleted from the table.
1487 	 */
1488 	table_pending_modify1_free(table);
1489 	table_pending_modify0_admit(table);
1490 
1491 	/* Add back all the pending delete entries, as none of them was deleted
1492 	 * from the table.
1493 	 */
1494 	table_pending_delete_admit(table);
1495 
1496 	/* Free up the pending default entry, as it is no longer going to be
1497 	 * added to the table.
1498 	 */
1499 	table_pending_default_free(table);
1500 }
1501 
1502 int
1503 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1504 {
1505 	struct rte_swx_table_state *ts;
1506 	int status = 0;
1507 	uint32_t i;
1508 
1509 	CHECK(ctl, EINVAL);
1510 
1511 	/* Operate the changes on the current ts_next before it becomes the new
1512 	 * ts.
1513 	 */
1514 	for (i = 0; i < ctl->info.n_tables; i++) {
1515 		status = table_rollfwd0(ctl, i, 0);
1516 		if (status)
1517 			goto rollback;
1518 	}
1519 
1520 	for (i = 0; i < ctl->info.n_tables; i++)
1521 		table_rollfwd1(ctl, i);
1522 
1523 	/* Swap the table state for the data plane. The current ts and ts_next
1524 	 * become the new ts_next and ts, respectively.
1525 	 */
1526 	rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1527 	usleep(100);
1528 	ts = ctl->ts;
1529 	ctl->ts = ctl->ts_next;
1530 	ctl->ts_next = ts;
1531 
1532 	/* Operate the changes on the current ts_next, which is the previous ts.
1533 	 */
1534 	for (i = 0; i < ctl->info.n_tables; i++) {
1535 		table_rollfwd0(ctl, i, 1);
1536 		table_rollfwd1(ctl, i);
1537 		table_rollfwd2(ctl, i);
1538 	}
1539 
1540 	return 0;
1541 
1542 rollback:
1543 	for (i = 0; i < ctl->info.n_tables; i++) {
1544 		table_rollback(ctl, i);
1545 		if (abort_on_fail)
1546 			table_abort(ctl, i);
1547 	}
1548 
1549 	return status;
1550 }
1551 
1552 void
1553 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1554 {
1555 	uint32_t i;
1556 
1557 	if (!ctl)
1558 		return;
1559 
1560 	for (i = 0; i < ctl->info.n_tables; i++)
1561 		table_abort(ctl, i);
1562 }
1563 
1564 static int
1565 token_is_comment(const char *token)
1566 {
1567 	if ((token[0] == '#') ||
1568 	    (token[0] == ';') ||
1569 	    ((token[0] == '/') && (token[1] == '/')))
1570 		return 1; /* TRUE. */
1571 
1572 	return 0; /* FALSE. */
1573 }
1574 
1575 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1576 
1577 struct rte_swx_table_entry *
1578 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1579 				      const char *table_name,
1580 				      const char *string,
1581 				      int *is_blank_or_comment)
1582 {
1583 	char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1584 	struct table *table;
1585 	struct action *action;
1586 	struct rte_swx_table_entry *entry = NULL;
1587 	char *s0 = NULL, *s;
1588 	uint32_t n_tokens = 0, arg_offset = 0, i;
1589 	int blank_or_comment = 0;
1590 
1591 	/* Check input arguments. */
1592 	if (!ctl)
1593 		goto error;
1594 
1595 	if (!table_name || !table_name[0])
1596 		goto error;
1597 
1598 	table = table_find(ctl, table_name);
1599 	if (!table)
1600 		goto error;
1601 
1602 	if (!string || !string[0])
1603 		goto error;
1604 
1605 	/* Memory allocation. */
1606 	s0 = strdup(string);
1607 	if (!s0)
1608 		goto error;
1609 
1610 	entry = table_entry_alloc(table);
1611 	if (!entry)
1612 		goto error;
1613 
1614 	/* Parse the string into tokens. */
1615 	for (s = s0; ; ) {
1616 		char *token;
1617 
1618 		token = strtok_r(s, " \f\n\r\t\v", &s);
1619 		if (!token || token_is_comment(token))
1620 			break;
1621 
1622 		if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1623 			goto error;
1624 
1625 		token_array[n_tokens] = token;
1626 		n_tokens++;
1627 	}
1628 
1629 	if (!n_tokens) {
1630 		blank_or_comment = 1;
1631 		goto error;
1632 	}
1633 
1634 	tokens = token_array;
1635 
1636 	/*
1637 	 * Match.
1638 	 */
1639 	if (n_tokens && strcmp(tokens[0], "match"))
1640 		goto action;
1641 
1642 	if (n_tokens < 1 + table->info.n_match_fields)
1643 		goto error;
1644 
1645 	for (i = 0; i < table->info.n_match_fields; i++) {
1646 		struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1647 		char *mf_val = tokens[1 + i], *mf_mask = NULL;
1648 		uint64_t val, mask = UINT64_MAX;
1649 		uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
1650 
1651 		/*
1652 		 * Mask.
1653 		 */
1654 		mf_mask = strchr(mf_val, '/');
1655 		if (mf_mask) {
1656 			*mf_mask = 0;
1657 			mf_mask++;
1658 
1659 			/* Parse. */
1660 			mask = strtoull(mf_mask, &mf_mask, 0);
1661 			if (mf_mask[0])
1662 				goto error;
1663 
1664 			/* Endianness conversion. */
1665 			if (mf->is_header)
1666 				mask = field_hton(mask, mf->n_bits);
1667 		}
1668 
1669 		/* Copy to entry. */
1670 		if (entry->key_mask)
1671 			memcpy(&entry->key_mask[offset],
1672 			       (uint8_t *)&mask,
1673 			       mf->n_bits / 8);
1674 
1675 		/*
1676 		 * Value.
1677 		 */
1678 		/* Parse. */
1679 		val = strtoull(mf_val, &mf_val, 0);
1680 		if (mf_val[0])
1681 			goto error;
1682 
1683 		/* Endianness conversion. */
1684 		if (mf->is_header)
1685 			val = field_hton(val, mf->n_bits);
1686 
1687 		/* Copy to entry. */
1688 		memcpy(&entry->key[offset],
1689 		       (uint8_t *)&val,
1690 		       mf->n_bits / 8);
1691 	}
1692 
1693 	tokens += 1 + table->info.n_match_fields;
1694 	n_tokens -= 1 + table->info.n_match_fields;
1695 
1696 	/*
1697 	 * Match priority.
1698 	 */
1699 	if (n_tokens && !strcmp(tokens[0], "priority")) {
1700 		char *priority = tokens[1];
1701 		uint32_t val;
1702 
1703 		if (n_tokens < 2)
1704 			goto error;
1705 
1706 		/* Parse. */
1707 		val = strtoul(priority, &priority, 0);
1708 		if (priority[0])
1709 			goto error;
1710 
1711 		/* Copy to entry. */
1712 		entry->key_priority = val;
1713 
1714 		tokens += 2;
1715 		n_tokens -= 2;
1716 	}
1717 
1718 	/*
1719 	 * Action.
1720 	 */
1721 action:
1722 	if (n_tokens && strcmp(tokens[0], "action"))
1723 		goto other;
1724 
1725 	if (n_tokens < 2)
1726 		goto error;
1727 
1728 	action = action_find(ctl, tokens[1]);
1729 	if (!action)
1730 		goto error;
1731 
1732 	if (n_tokens < 2 + action->info.n_args * 2)
1733 		goto error;
1734 
1735 	/* action_id. */
1736 	entry->action_id = action - ctl->actions;
1737 
1738 	/* action_data. */
1739 	for (i = 0; i < action->info.n_args; i++) {
1740 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1741 		char *arg_name, *arg_val;
1742 		uint64_t val;
1743 
1744 		arg_name = tokens[2 + i * 2];
1745 		arg_val = tokens[2 + i * 2 + 1];
1746 
1747 		if (strcmp(arg_name, arg->name))
1748 			goto error;
1749 
1750 		val = strtoull(arg_val, &arg_val, 0);
1751 		if (arg_val[0])
1752 			goto error;
1753 
1754 		/* Endianness conversion. */
1755 		if (arg->is_network_byte_order)
1756 			val = field_hton(val, arg->n_bits);
1757 
1758 		/* Copy to entry. */
1759 		memcpy(&entry->action_data[arg_offset],
1760 		       (uint8_t *)&val,
1761 		       arg->n_bits / 8);
1762 
1763 		arg_offset += arg->n_bits / 8;
1764 	}
1765 
1766 	tokens += 2 + action->info.n_args * 2;
1767 	n_tokens -= 2 + action->info.n_args * 2;
1768 
1769 other:
1770 	if (n_tokens)
1771 		goto error;
1772 
1773 	free(s0);
1774 	return entry;
1775 
1776 error:
1777 	table_entry_free(entry);
1778 	free(s0);
1779 	if (is_blank_or_comment)
1780 		*is_blank_or_comment = blank_or_comment;
1781 	return NULL;
1782 }
1783 
1784 static void
1785 table_entry_printf(FILE *f,
1786 		   struct rte_swx_ctl_pipeline *ctl,
1787 		   struct table *table,
1788 		   struct rte_swx_table_entry *entry)
1789 {
1790 	struct action *action = &ctl->actions[entry->action_id];
1791 	uint32_t i;
1792 
1793 	fprintf(f, "match ");
1794 	for (i = 0; i < table->params.key_size; i++)
1795 		fprintf(f, "%02x", entry->key[i]);
1796 
1797 	if (entry->key_mask) {
1798 		fprintf(f, "/");
1799 		for (i = 0; i < table->params.key_size; i++)
1800 			fprintf(f, "%02x", entry->key_mask[i]);
1801 	}
1802 
1803 	fprintf(f, " priority %u", entry->key_priority);
1804 
1805 	fprintf(f, " action %s ", action->info.name);
1806 	for (i = 0; i < action->data_size; i++)
1807 		fprintf(f, "%02x", entry->action_data[i]);
1808 
1809 	fprintf(f, "\n");
1810 }
1811 
1812 int
1813 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1814 				   struct rte_swx_ctl_pipeline *ctl,
1815 				   const char *table_name)
1816 {
1817 	struct table *table;
1818 	struct rte_swx_table_entry *entry;
1819 	uint32_t n_entries = 0, i;
1820 
1821 	if (!f || !ctl || !table_name || !table_name[0])
1822 		return -EINVAL;
1823 
1824 	table = table_find(ctl, table_name);
1825 	if (!table)
1826 		return -EINVAL;
1827 
1828 	/* Table. */
1829 	fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1830 		table->info.name,
1831 		table->params.key_size,
1832 		table->params.key_offset);
1833 
1834 	for (i = 0; i < table->params.key_size; i++)
1835 		fprintf(f, "%02x", table->params.key_mask0[i]);
1836 
1837 	fprintf(f, "], action data size %u bytes\n",
1838 		table->params.action_data_size);
1839 
1840 	/* Table entries. */
1841 	TAILQ_FOREACH(entry, &table->entries, node) {
1842 		table_entry_printf(f, ctl, table, entry);
1843 		n_entries++;
1844 	}
1845 
1846 	TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1847 		table_entry_printf(f, ctl, table, entry);
1848 		n_entries++;
1849 	}
1850 
1851 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
1852 		table_entry_printf(f, ctl, table, entry);
1853 		n_entries++;
1854 	}
1855 
1856 	fprintf(f, "# Table %s currently has %u entries.\n",
1857 		table_name,
1858 		n_entries);
1859 	return 0;
1860 }
1861