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 	struct rte_swx_ctl_table_action_info *actions;
42 	struct rte_swx_table_ops ops;
43 	struct rte_swx_table_params params;
44 
45 	struct rte_swx_table_entry_list entries;
46 	struct rte_swx_table_entry_list pending_add;
47 	struct rte_swx_table_entry_list pending_modify0;
48 	struct rte_swx_table_entry_list pending_modify1;
49 	struct rte_swx_table_entry_list pending_delete;
50 	struct rte_swx_table_entry *pending_default;
51 
52 	int is_stub;
53 	uint32_t n_add;
54 	uint32_t n_modify;
55 	uint32_t n_delete;
56 };
57 
58 struct rte_swx_ctl_pipeline {
59 	struct rte_swx_ctl_pipeline_info info;
60 	struct rte_swx_pipeline *p;
61 	struct action *actions;
62 	struct table *tables;
63 	struct rte_swx_table_state *ts;
64 	struct rte_swx_table_state *ts_next;
65 	int numa_node;
66 };
67 
68 static struct action *
action_find(struct rte_swx_ctl_pipeline * ctl,const char * action_name)69 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
70 {
71 	uint32_t i;
72 
73 	for (i = 0; i < ctl->info.n_actions; i++) {
74 		struct action *a = &ctl->actions[i];
75 
76 		if (!strcmp(action_name, a->info.name))
77 			return a;
78 	}
79 
80 	return NULL;
81 }
82 
83 static void
action_free(struct rte_swx_ctl_pipeline * ctl)84 action_free(struct rte_swx_ctl_pipeline *ctl)
85 {
86 	uint32_t i;
87 
88 	if (!ctl->actions)
89 		return;
90 
91 	for (i = 0; i < ctl->info.n_actions; i++) {
92 		struct action *action = &ctl->actions[i];
93 
94 		free(action->args);
95 	}
96 
97 	free(ctl->actions);
98 	ctl->actions = NULL;
99 }
100 
101 static struct table *
table_find(struct rte_swx_ctl_pipeline * ctl,const char * table_name)102 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
103 {
104 	uint32_t i;
105 
106 	for (i = 0; i < ctl->info.n_tables; i++) {
107 		struct table *table = &ctl->tables[i];
108 
109 		if (!strcmp(table_name, table->info.name))
110 			return table;
111 	}
112 
113 	return NULL;
114 }
115 
116 static int
table_params_get(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)117 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
118 {
119 	struct table *table = &ctl->tables[table_id];
120 	uint8_t *key_mask = NULL;
121 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
122 	uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
123 
124 	if (table->info.n_match_fields) {
125 		struct rte_swx_ctl_table_match_field_info *first, *last;
126 		uint32_t i;
127 
128 		first = &table->mf[0];
129 		last = &table->mf[table->info.n_match_fields - 1];
130 
131 		/* match_type. */
132 		for (i = 0; i < table->info.n_match_fields; i++) {
133 			struct rte_swx_ctl_table_match_field_info *f;
134 
135 			f = &table->mf[i];
136 			if (f->match_type != RTE_SWX_TABLE_MATCH_EXACT)
137 				break;
138 		}
139 
140 		if (i == table->info.n_match_fields)
141 			match_type = RTE_SWX_TABLE_MATCH_EXACT;
142 		else if ((i == table->info.n_match_fields - 1) &&
143 			 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
144 			match_type = RTE_SWX_TABLE_MATCH_LPM;
145 
146 		/* key_offset. */
147 		key_offset = first->offset / 8;
148 
149 		/* key_size. */
150 		key_size = (last->offset + last->n_bits - first->offset) / 8;
151 
152 		/* key_mask. */
153 		key_mask = calloc(1, key_size);
154 		CHECK(key_mask, ENOMEM);
155 
156 		for (i = 0; i < table->info.n_match_fields; i++) {
157 			struct rte_swx_ctl_table_match_field_info *f;
158 			uint32_t start;
159 			size_t size;
160 
161 			f = &table->mf[i];
162 			start = (f->offset - first->offset) / 8;
163 			size = f->n_bits / 8;
164 
165 			memset(&key_mask[start], 0xFF, size);
166 		}
167 	}
168 
169 	/* action_data_size. */
170 	for (i = 0; i < table->info.n_actions; i++) {
171 		uint32_t action_id = table->actions[i].action_id;
172 		struct action *a = &ctl->actions[action_id];
173 
174 		if (a->data_size > action_data_size)
175 			action_data_size = a->data_size;
176 	}
177 
178 	/* Fill in. */
179 	table->params.match_type = match_type;
180 	table->params.key_size = key_size;
181 	table->params.key_offset = key_offset;
182 	table->params.key_mask0 = key_mask;
183 	table->params.action_data_size = action_data_size;
184 	table->params.n_keys_max = table->info.size;
185 
186 	return 0;
187 }
188 
189 static void
table_entry_free(struct rte_swx_table_entry * entry)190 table_entry_free(struct rte_swx_table_entry *entry)
191 {
192 	if (!entry)
193 		return;
194 
195 	free(entry->key);
196 	free(entry->key_mask);
197 	free(entry->action_data);
198 	free(entry);
199 }
200 
201 static struct rte_swx_table_entry *
table_entry_alloc(struct table * table)202 table_entry_alloc(struct table *table)
203 {
204 	struct rte_swx_table_entry *entry;
205 
206 	entry = calloc(1, sizeof(struct rte_swx_table_entry));
207 	if (!entry)
208 		goto error;
209 
210 	/* key, key_mask. */
211 	if (!table->is_stub) {
212 		entry->key = calloc(1, table->params.key_size);
213 		if (!entry->key)
214 			goto error;
215 
216 		if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
217 			entry->key_mask = calloc(1, table->params.key_size);
218 			if (!entry->key_mask)
219 				goto error;
220 		}
221 	}
222 
223 	/* action_data. */
224 	if (table->params.action_data_size) {
225 		entry->action_data = calloc(1, table->params.action_data_size);
226 		if (!entry->action_data)
227 			goto error;
228 	}
229 
230 	return entry;
231 
232 error:
233 	table_entry_free(entry);
234 	return NULL;
235 }
236 
237 static int
table_entry_check(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_check,int data_check)238 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
239 		  uint32_t table_id,
240 		  struct rte_swx_table_entry *entry,
241 		  int key_check,
242 		  int data_check)
243 {
244 	struct table *table = &ctl->tables[table_id];
245 
246 	CHECK(entry, EINVAL);
247 
248 	if (key_check) {
249 		if (table->is_stub) {
250 			/* key. */
251 			CHECK(!entry->key, EINVAL);
252 
253 			/* key_mask. */
254 			CHECK(!entry->key_mask, EINVAL);
255 		} else {
256 			/* key. */
257 			CHECK(entry->key, EINVAL);
258 
259 			/* key_mask. */
260 			switch (table->params.match_type) {
261 			case RTE_SWX_TABLE_MATCH_WILDCARD:
262 				break;
263 
264 			case RTE_SWX_TABLE_MATCH_LPM:
265 				/* TBD Check that key mask is prefix. */
266 				break;
267 
268 			case RTE_SWX_TABLE_MATCH_EXACT:
269 				CHECK(!entry->key_mask, EINVAL);
270 				break;
271 
272 			default:
273 				CHECK(0, EINVAL);
274 			}
275 		}
276 	}
277 
278 	if (data_check) {
279 		struct action *a;
280 		uint32_t i;
281 
282 		/* action_id. */
283 		for (i = 0; i < table->info.n_actions; i++)
284 			if (entry->action_id == table->actions[i].action_id)
285 				break;
286 
287 		CHECK(i < table->info.n_actions, EINVAL);
288 
289 		/* action_data. */
290 		a = &ctl->actions[entry->action_id];
291 		CHECK((a->data_size && entry->action_data) ||
292 		      (!a->data_size && !entry->action_data), EINVAL);
293 	}
294 
295 	return 0;
296 }
297 
298 static struct rte_swx_table_entry *
table_entry_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_duplicate,int data_duplicate)299 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
300 		      uint32_t table_id,
301 		      struct rte_swx_table_entry *entry,
302 		      int key_duplicate,
303 		      int data_duplicate)
304 {
305 	struct table *table = &ctl->tables[table_id];
306 	struct rte_swx_table_entry *new_entry = NULL;
307 
308 	if (!entry)
309 		goto error;
310 
311 	new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
312 	if (!new_entry)
313 		goto error;
314 
315 	if (key_duplicate && !table->is_stub) {
316 		/* key. */
317 		if (!entry->key)
318 			goto error;
319 
320 		new_entry->key = malloc(table->params.key_size);
321 		if (!new_entry->key)
322 			goto error;
323 
324 		memcpy(new_entry->key, entry->key, table->params.key_size);
325 
326 		/* key_signature. */
327 		new_entry->key_signature = entry->key_signature;
328 
329 		/* key_mask. */
330 		if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
331 			if (!entry->key_mask)
332 				goto error;
333 
334 			new_entry->key_mask = malloc(table->params.key_size);
335 			if (!new_entry->key_mask)
336 				goto error;
337 
338 			memcpy(new_entry->key_mask,
339 			       entry->key_mask,
340 			       table->params.key_size);
341 		}
342 	}
343 
344 	if (data_duplicate) {
345 		struct action *a;
346 		uint32_t i;
347 
348 		/* action_id. */
349 		for (i = 0; i < table->info.n_actions; i++)
350 			if (entry->action_id == table->actions[i].action_id)
351 				break;
352 
353 		if (i >= table->info.n_actions)
354 			goto error;
355 
356 		new_entry->action_id = entry->action_id;
357 
358 		/* action_data. */
359 		a = &ctl->actions[entry->action_id];
360 		if (a->data_size) {
361 			if (!entry->action_data)
362 				goto error;
363 
364 			new_entry->action_data = malloc(a->data_size);
365 			if (!new_entry->action_data)
366 				goto error;
367 
368 			memcpy(new_entry->action_data,
369 			       entry->action_data,
370 			       a->data_size);
371 		}
372 	}
373 
374 	return new_entry;
375 
376 error:
377 	table_entry_free(new_entry);
378 	return NULL;
379 }
380 
381 static int
entry_keycmp_em(struct rte_swx_table_entry * e0,struct rte_swx_table_entry * e1,uint32_t key_size)382 entry_keycmp_em(struct rte_swx_table_entry *e0,
383 		struct rte_swx_table_entry *e1,
384 		uint32_t key_size)
385 {
386 	if (e0->key_signature != e1->key_signature)
387 		return 1; /* Not equal. */
388 
389 	if (memcmp(e0->key, e1->key, key_size))
390 		return 1; /* Not equal. */
391 
392 	return 0; /* Equal */
393 }
394 
395 static int
entry_keycmp_wm(struct rte_swx_table_entry * e0 __rte_unused,struct rte_swx_table_entry * e1 __rte_unused,uint32_t key_size __rte_unused)396 entry_keycmp_wm(struct rte_swx_table_entry *e0 __rte_unused,
397 		struct rte_swx_table_entry *e1 __rte_unused,
398 		uint32_t key_size __rte_unused)
399 {
400 	/* TBD */
401 
402 	return 1; /* Not equal */
403 }
404 
405 static int
entry_keycmp_lpm(struct rte_swx_table_entry * e0 __rte_unused,struct rte_swx_table_entry * e1 __rte_unused,uint32_t key_size __rte_unused)406 entry_keycmp_lpm(struct rte_swx_table_entry *e0 __rte_unused,
407 		 struct rte_swx_table_entry *e1 __rte_unused,
408 		 uint32_t key_size __rte_unused)
409 {
410 	/* TBD */
411 
412 	return 1; /* Not equal */
413 }
414 
415 static int
table_entry_keycmp(struct table * table,struct rte_swx_table_entry * e0,struct rte_swx_table_entry * e1)416 table_entry_keycmp(struct table *table,
417 		   struct rte_swx_table_entry *e0,
418 		   struct rte_swx_table_entry *e1)
419 {
420 	switch (table->params.match_type) {
421 	case RTE_SWX_TABLE_MATCH_EXACT:
422 		return entry_keycmp_em(e0, e1, table->params.key_size);
423 
424 	case RTE_SWX_TABLE_MATCH_WILDCARD:
425 		return entry_keycmp_wm(e0, e1, table->params.key_size);
426 
427 	case RTE_SWX_TABLE_MATCH_LPM:
428 		return entry_keycmp_lpm(e0, e1, table->params.key_size);
429 
430 	default:
431 		return 1; /* Not equal. */
432 	}
433 }
434 
435 static struct rte_swx_table_entry *
table_entries_find(struct table * table,struct rte_swx_table_entry * entry)436 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
437 {
438 	struct rte_swx_table_entry *e;
439 
440 	TAILQ_FOREACH(e, &table->entries, node)
441 		if (!table_entry_keycmp(table, entry, e))
442 			return e; /* Found. */
443 
444 	return NULL; /* Not found. */
445 }
446 
447 static void
table_entries_free(struct table * table)448 table_entries_free(struct table *table)
449 {
450 	for ( ; ; ) {
451 		struct rte_swx_table_entry *entry;
452 
453 		entry = TAILQ_FIRST(&table->entries);
454 		if (!entry)
455 			break;
456 
457 		TAILQ_REMOVE(&table->entries, entry, node);
458 		table_entry_free(entry);
459 	}
460 }
461 
462 static struct rte_swx_table_entry *
table_pending_add_find(struct table * table,struct rte_swx_table_entry * entry)463 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
464 {
465 	struct rte_swx_table_entry *e;
466 
467 	TAILQ_FOREACH(e, &table->pending_add, node)
468 		if (!table_entry_keycmp(table, entry, e))
469 			return e; /* Found. */
470 
471 	return NULL; /* Not found. */
472 }
473 
474 static void
table_pending_add_admit(struct table * table)475 table_pending_add_admit(struct table *table)
476 {
477 	TAILQ_CONCAT(&table->entries, &table->pending_add, node);
478 }
479 
480 static void
table_pending_add_free(struct table * table)481 table_pending_add_free(struct table *table)
482 {
483 	for ( ; ; ) {
484 		struct rte_swx_table_entry *entry;
485 
486 		entry = TAILQ_FIRST(&table->pending_add);
487 		if (!entry)
488 			break;
489 
490 		TAILQ_REMOVE(&table->pending_add, entry, node);
491 		table_entry_free(entry);
492 	}
493 }
494 
495 static struct rte_swx_table_entry *
table_pending_modify0_find(struct table * table,struct rte_swx_table_entry * entry)496 table_pending_modify0_find(struct table *table,
497 			   struct rte_swx_table_entry *entry)
498 {
499 	struct rte_swx_table_entry *e;
500 
501 	TAILQ_FOREACH(e, &table->pending_modify0, node)
502 		if (!table_entry_keycmp(table, entry, e))
503 			return e; /* Found. */
504 
505 	return NULL; /* Not found. */
506 }
507 
508 static void
table_pending_modify0_admit(struct table * table)509 table_pending_modify0_admit(struct table *table)
510 {
511 	TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
512 }
513 
514 static void
table_pending_modify0_free(struct table * table)515 table_pending_modify0_free(struct table *table)
516 {
517 	for ( ; ; ) {
518 		struct rte_swx_table_entry *entry;
519 
520 		entry = TAILQ_FIRST(&table->pending_modify0);
521 		if (!entry)
522 			break;
523 
524 		TAILQ_REMOVE(&table->pending_modify0, entry, node);
525 		table_entry_free(entry);
526 	}
527 }
528 
529 static struct rte_swx_table_entry *
table_pending_modify1_find(struct table * table,struct rte_swx_table_entry * entry)530 table_pending_modify1_find(struct table *table,
531 			   struct rte_swx_table_entry *entry)
532 {
533 	struct rte_swx_table_entry *e;
534 
535 	TAILQ_FOREACH(e, &table->pending_modify1, node)
536 		if (!table_entry_keycmp(table, entry, e))
537 			return e; /* Found. */
538 
539 	return NULL; /* Not found. */
540 }
541 
542 static void
table_pending_modify1_admit(struct table * table)543 table_pending_modify1_admit(struct table *table)
544 {
545 	TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
546 }
547 
548 static void
table_pending_modify1_free(struct table * table)549 table_pending_modify1_free(struct table *table)
550 {
551 	for ( ; ; ) {
552 		struct rte_swx_table_entry *entry;
553 
554 		entry = TAILQ_FIRST(&table->pending_modify1);
555 		if (!entry)
556 			break;
557 
558 		TAILQ_REMOVE(&table->pending_modify1, entry, node);
559 		table_entry_free(entry);
560 	}
561 }
562 
563 static struct rte_swx_table_entry *
table_pending_delete_find(struct table * table,struct rte_swx_table_entry * entry)564 table_pending_delete_find(struct table *table,
565 			  struct rte_swx_table_entry *entry)
566 {
567 	struct rte_swx_table_entry *e;
568 
569 	TAILQ_FOREACH(e, &table->pending_delete, node)
570 		if (!table_entry_keycmp(table, entry, e))
571 			return e; /* Found. */
572 
573 	return NULL; /* Not found. */
574 }
575 
576 static void
table_pending_delete_admit(struct table * table)577 table_pending_delete_admit(struct table *table)
578 {
579 	TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
580 }
581 
582 static void
table_pending_delete_free(struct table * table)583 table_pending_delete_free(struct table *table)
584 {
585 	for ( ; ; ) {
586 		struct rte_swx_table_entry *entry;
587 
588 		entry = TAILQ_FIRST(&table->pending_delete);
589 		if (!entry)
590 			break;
591 
592 		TAILQ_REMOVE(&table->pending_delete, entry, node);
593 		table_entry_free(entry);
594 	}
595 }
596 
597 static void
table_pending_default_free(struct table * table)598 table_pending_default_free(struct table *table)
599 {
600 	if (!table->pending_default)
601 		return;
602 
603 	free(table->pending_default->action_data);
604 	free(table->pending_default);
605 	table->pending_default = NULL;
606 }
607 
608 static void
table_free(struct rte_swx_ctl_pipeline * ctl)609 table_free(struct rte_swx_ctl_pipeline *ctl)
610 {
611 	uint32_t i;
612 
613 	if (!ctl->tables)
614 		return;
615 
616 	for (i = 0; i < ctl->info.n_tables; i++) {
617 		struct table *table = &ctl->tables[i];
618 
619 		free(table->mf);
620 		free(table->actions);
621 		free(table->params.key_mask0);
622 
623 		table_entries_free(table);
624 		table_pending_add_free(table);
625 		table_pending_modify0_free(table);
626 		table_pending_modify1_free(table);
627 		table_pending_delete_free(table);
628 		table_pending_default_free(table);
629 	}
630 
631 	free(ctl->tables);
632 	ctl->tables = NULL;
633 }
634 
635 static void
table_state_free(struct rte_swx_ctl_pipeline * ctl)636 table_state_free(struct rte_swx_ctl_pipeline *ctl)
637 {
638 	uint32_t i;
639 
640 	if (!ctl->ts_next)
641 		return;
642 
643 	/* For each table, free its table state. */
644 	for (i = 0; i < ctl->info.n_tables; i++) {
645 		struct table *table = &ctl->tables[i];
646 		struct rte_swx_table_state *ts = &ctl->ts_next[i];
647 
648 		/* Default action data. */
649 		free(ts->default_action_data);
650 
651 		/* Table object. */
652 		if (!table->is_stub && table->ops.free && ts->obj)
653 			table->ops.free(ts->obj);
654 	}
655 
656 	free(ctl->ts_next);
657 	ctl->ts_next = NULL;
658 }
659 
660 static int
table_state_create(struct rte_swx_ctl_pipeline * ctl)661 table_state_create(struct rte_swx_ctl_pipeline *ctl)
662 {
663 	int status = 0;
664 	uint32_t i;
665 
666 	ctl->ts_next = calloc(ctl->info.n_tables,
667 			      sizeof(struct rte_swx_table_state));
668 	if (!ctl->ts_next) {
669 		status = -ENOMEM;
670 		goto error;
671 	}
672 
673 	for (i = 0; i < ctl->info.n_tables; i++) {
674 		struct table *table = &ctl->tables[i];
675 		struct rte_swx_table_state *ts = &ctl->ts[i];
676 		struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
677 
678 		/* Table object. */
679 		if (!table->is_stub) {
680 			ts_next->obj = table->ops.create(&table->params,
681 							 &table->entries,
682 							 table->info.args,
683 							 ctl->numa_node);
684 			if (!ts_next->obj) {
685 				status = -ENODEV;
686 				goto error;
687 			}
688 		}
689 
690 		/* Default action data: duplicate from current table state. */
691 		ts_next->default_action_data =
692 			malloc(table->params.action_data_size);
693 		if (!ts_next->default_action_data) {
694 			status = -ENOMEM;
695 			goto error;
696 		}
697 
698 		memcpy(ts_next->default_action_data,
699 		       ts->default_action_data,
700 		       table->params.action_data_size);
701 
702 		ts_next->default_action_id = ts->default_action_id;
703 	}
704 
705 	return 0;
706 
707 error:
708 	table_state_free(ctl);
709 	return status;
710 }
711 
712 void
rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline * ctl)713 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
714 {
715 	if (!ctl)
716 		return;
717 
718 	action_free(ctl);
719 
720 	table_state_free(ctl);
721 
722 	table_free(ctl);
723 
724 	free(ctl);
725 }
726 
727 struct rte_swx_ctl_pipeline *
rte_swx_ctl_pipeline_create(struct rte_swx_pipeline * p)728 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
729 {
730 	struct rte_swx_ctl_pipeline *ctl = NULL;
731 	uint32_t i;
732 	int status;
733 
734 	if (!p)
735 		goto error;
736 
737 	ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
738 	if (!ctl)
739 		goto error;
740 
741 	/* info. */
742 	status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
743 	if (status)
744 		goto error;
745 
746 	/* numa_node. */
747 	status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
748 	if (status)
749 		goto error;
750 
751 	/* p. */
752 	ctl->p = p;
753 
754 	/* actions. */
755 	ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
756 	if (!ctl->actions)
757 		goto error;
758 
759 	for (i = 0; i < ctl->info.n_actions; i++) {
760 		struct action *a = &ctl->actions[i];
761 		uint32_t j;
762 
763 		/* info. */
764 		status = rte_swx_ctl_action_info_get(p, i, &a->info);
765 		if (status)
766 			goto error;
767 
768 		/* args. */
769 		a->args = calloc(a->info.n_args,
770 				 sizeof(struct rte_swx_ctl_action_arg_info));
771 		if (!a->args)
772 			goto error;
773 
774 		for (j = 0; j < a->info.n_args; j++) {
775 			status = rte_swx_ctl_action_arg_info_get(p,
776 								 i,
777 								 j,
778 								 &a->args[j]);
779 			if (status)
780 				goto error;
781 		}
782 
783 		/* data_size. */
784 		for (j = 0; j < a->info.n_args; j++) {
785 			struct rte_swx_ctl_action_arg_info *info = &a->args[j];
786 
787 			a->data_size += info->n_bits;
788 		}
789 
790 		a->data_size = (a->data_size + 7) / 8;
791 	}
792 
793 	/* tables. */
794 	ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
795 	if (!ctl->tables)
796 		goto error;
797 
798 	for (i = 0; i < ctl->info.n_tables; i++) {
799 		struct table *t = &ctl->tables[i];
800 
801 		TAILQ_INIT(&t->entries);
802 		TAILQ_INIT(&t->pending_add);
803 		TAILQ_INIT(&t->pending_modify0);
804 		TAILQ_INIT(&t->pending_modify1);
805 		TAILQ_INIT(&t->pending_delete);
806 	}
807 
808 	for (i = 0; i < ctl->info.n_tables; i++) {
809 		struct table *t = &ctl->tables[i];
810 		uint32_t j;
811 
812 		/* info. */
813 		status = rte_swx_ctl_table_info_get(p, i, &t->info);
814 		if (status)
815 			goto error;
816 
817 		/* mf. */
818 		t->mf = calloc(t->info.n_match_fields,
819 			sizeof(struct rte_swx_ctl_table_match_field_info));
820 		if (!t->mf)
821 			goto error;
822 
823 		for (j = 0; j < t->info.n_match_fields; j++) {
824 			status = rte_swx_ctl_table_match_field_info_get(p,
825 				i,
826 				j,
827 				&t->mf[j]);
828 			if (status)
829 				goto error;
830 		}
831 
832 		/* actions. */
833 		t->actions = calloc(t->info.n_actions,
834 			sizeof(struct rte_swx_ctl_table_action_info));
835 		if (!t->actions)
836 			goto error;
837 
838 		for (j = 0; j < t->info.n_actions; j++) {
839 			status = rte_swx_ctl_table_action_info_get(p,
840 				i,
841 				j,
842 				&t->actions[j]);
843 			if (status ||
844 			    t->actions[j].action_id >= ctl->info.n_actions)
845 				goto error;
846 		}
847 
848 		/* ops, is_stub. */
849 		status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
850 		if (status)
851 			goto error;
852 
853 		if ((t->is_stub && t->info.n_match_fields) ||
854 		    (!t->is_stub && !t->info.n_match_fields))
855 			goto error;
856 
857 		/* params. */
858 		status = table_params_get(ctl, i);
859 		if (status)
860 			goto error;
861 	}
862 
863 	/* ts. */
864 	status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
865 	if (status)
866 		goto error;
867 
868 	/* ts_next. */
869 	status = table_state_create(ctl);
870 	if (status)
871 		goto error;
872 
873 	return ctl;
874 
875 error:
876 	rte_swx_ctl_pipeline_free(ctl);
877 	return NULL;
878 }
879 
880 int
rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)881 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
882 				     const char *table_name,
883 				     struct rte_swx_table_entry *entry)
884 {
885 	struct table *table;
886 	struct rte_swx_table_entry *new_entry, *existing_entry;
887 	uint32_t table_id;
888 
889 	CHECK(ctl, EINVAL);
890 	CHECK(table_name && table_name[0], EINVAL);
891 
892 	table = table_find(ctl, table_name);
893 	CHECK(table, EINVAL);
894 	table_id = table - ctl->tables;
895 
896 	new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
897 	CHECK(new_entry, ENOMEM);
898 
899 	/* The new entry is found in the table->entries list:
900 	 * - Add the new entry to the table->pending_modify1 list;
901 	 * - Move the existing entry from the table->entries list to the
902 	 *   table->pending_modify0 list.
903 	 */
904 	existing_entry = table_entries_find(table, entry);
905 	if (existing_entry) {
906 		TAILQ_INSERT_TAIL(&table->pending_modify1,
907 				  new_entry,
908 				  node);
909 
910 		TAILQ_REMOVE(&table->entries,
911 			     existing_entry,
912 			     node);
913 
914 		TAILQ_INSERT_TAIL(&table->pending_modify0,
915 				  existing_entry,
916 				  node);
917 
918 		return 0;
919 	}
920 
921 	/* The new entry is found in the table->pending_add list:
922 	 * - Replace the entry in the table->pending_add list with the new entry
923 	 *   (and free the replaced entry).
924 	 */
925 	existing_entry = table_pending_add_find(table, entry);
926 	if (existing_entry) {
927 		TAILQ_INSERT_AFTER(&table->pending_add,
928 				   existing_entry,
929 				   new_entry,
930 				   node);
931 
932 		TAILQ_REMOVE(&table->pending_add,
933 			     existing_entry,
934 			     node);
935 
936 		table_entry_free(existing_entry);
937 
938 		return 0;
939 	}
940 
941 	/* The new entry is found in the table->pending_modify1 list:
942 	 * - Replace the entry in the table->pending_modify1 list with the new
943 	 *   entry (and free the replaced entry).
944 	 */
945 	existing_entry = table_pending_modify1_find(table, entry);
946 	if (existing_entry) {
947 		TAILQ_INSERT_AFTER(&table->pending_modify1,
948 				   existing_entry,
949 				   new_entry,
950 				   node);
951 
952 		TAILQ_REMOVE(&table->pending_modify1,
953 			     existing_entry,
954 			     node);
955 
956 		table_entry_free(existing_entry);
957 
958 		return 0;
959 	}
960 
961 	/* The new entry is found in the table->pending_delete list:
962 	 * - Add the new entry to the table->pending_modify1 list;
963 	 * - Move the existing entry from the table->pending_delete list to the
964 	 *   table->pending_modify0 list.
965 	 */
966 	existing_entry = table_pending_delete_find(table, entry);
967 	if (existing_entry) {
968 		TAILQ_INSERT_TAIL(&table->pending_modify1,
969 				  new_entry,
970 				  node);
971 
972 		TAILQ_REMOVE(&table->pending_delete,
973 			     existing_entry,
974 			     node);
975 
976 		TAILQ_INSERT_TAIL(&table->pending_modify0,
977 				  existing_entry,
978 				  node);
979 
980 		return 0;
981 	}
982 
983 	/* The new entry is not found in any of the above lists:
984 	 * - Add the new entry to the table->pending_add list.
985 	 */
986 	TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
987 
988 	return 0;
989 }
990 
991 int
rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)992 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
993 					const char *table_name,
994 					struct rte_swx_table_entry *entry)
995 {
996 	struct table *table;
997 	struct rte_swx_table_entry *existing_entry;
998 	uint32_t table_id;
999 
1000 	CHECK(ctl, EINVAL);
1001 
1002 	CHECK(table_name && table_name[0], EINVAL);
1003 	table = table_find(ctl, table_name);
1004 	CHECK(table, EINVAL);
1005 	table_id = table - ctl->tables;
1006 
1007 	CHECK(entry, EINVAL);
1008 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1009 
1010 	/* The entry is found in the table->entries list:
1011 	 * - Move the existing entry from the table->entries list to to the
1012 	 *   table->pending_delete list.
1013 	 */
1014 	existing_entry = table_entries_find(table, entry);
1015 	if (existing_entry) {
1016 		TAILQ_REMOVE(&table->entries,
1017 			     existing_entry,
1018 			     node);
1019 
1020 		TAILQ_INSERT_TAIL(&table->pending_delete,
1021 				  existing_entry,
1022 				  node);
1023 
1024 		return 0;
1025 	}
1026 
1027 	/* The entry is found in the table->pending_add list:
1028 	 * - Remove the entry from the table->pending_add list and free it.
1029 	 */
1030 	existing_entry = table_pending_add_find(table, entry);
1031 	if (existing_entry) {
1032 		TAILQ_REMOVE(&table->pending_add,
1033 			     existing_entry,
1034 			     node);
1035 
1036 		table_entry_free(existing_entry);
1037 	}
1038 
1039 	/* The entry is found in the table->pending_modify1 list:
1040 	 * - Free the entry in the table->pending_modify1 list;
1041 	 * - Move the existing entry from the table->pending_modify0 list to the
1042 	 *   table->pending_delete list.
1043 	 */
1044 	existing_entry = table_pending_modify1_find(table, entry);
1045 	if (existing_entry) {
1046 		struct rte_swx_table_entry *real_existing_entry;
1047 
1048 		TAILQ_REMOVE(&table->pending_modify1,
1049 			     existing_entry,
1050 			     node);
1051 
1052 		table_entry_free(existing_entry);
1053 
1054 		real_existing_entry = table_pending_modify0_find(table, entry);
1055 		CHECK(real_existing_entry, EINVAL); /* Coverity. */
1056 
1057 		TAILQ_REMOVE(&table->pending_modify0,
1058 			     real_existing_entry,
1059 			     node);
1060 
1061 		TAILQ_INSERT_TAIL(&table->pending_delete,
1062 				  real_existing_entry,
1063 				  node);
1064 
1065 		return 0;
1066 	}
1067 
1068 	/* The entry is found in the table->pending_delete list:
1069 	 * - Do nothing: the existing entry is already in the
1070 	 *   table->pending_delete list, i.e. already marked for delete, so
1071 	 *   simply keep it there as it is.
1072 	 */
1073 
1074 	/* The entry is not found in any of the above lists:
1075 	 * - Do nothing: no existing entry to delete.
1076 	 */
1077 
1078 	return 0;
1079 }
1080 
1081 int
rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)1082 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1083 					     const char *table_name,
1084 					     struct rte_swx_table_entry *entry)
1085 {
1086 	struct table *table;
1087 	struct rte_swx_table_entry *new_entry;
1088 	uint32_t table_id;
1089 
1090 	CHECK(ctl, EINVAL);
1091 
1092 	CHECK(table_name && table_name[0], EINVAL);
1093 	table = table_find(ctl, table_name);
1094 	CHECK(table, EINVAL);
1095 	table_id = table - ctl->tables;
1096 	CHECK(!table->info.default_action_is_const, EINVAL);
1097 
1098 	new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1099 	CHECK(new_entry, ENOMEM);
1100 
1101 	table_pending_default_free(table);
1102 
1103 	table->pending_default = new_entry;
1104 	return 0;
1105 }
1106 
1107 static int
table_rollfwd0(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1108 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1109 {
1110 	struct table *table = &ctl->tables[table_id];
1111 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1112 	struct rte_swx_table_entry *entry;
1113 
1114 	/* Reset counters. */
1115 	table->n_add = 0;
1116 	table->n_modify = 0;
1117 	table->n_delete = 0;
1118 
1119 	/* Add pending rules. */
1120 	TAILQ_FOREACH(entry, &table->pending_add, node) {
1121 		int status;
1122 
1123 		status = table->ops.add(ts_next->obj, entry);
1124 		if (status)
1125 			return status;
1126 
1127 		table->n_add++;
1128 	}
1129 
1130 	/* Modify pending rules. */
1131 	TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1132 		int status;
1133 
1134 		status = table->ops.add(ts_next->obj, entry);
1135 		if (status)
1136 			return status;
1137 
1138 		table->n_modify++;
1139 	}
1140 
1141 	/* Delete pending rules. */
1142 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
1143 		int status;
1144 
1145 		status = table->ops.del(ts_next->obj, entry);
1146 		if (status)
1147 			return status;
1148 
1149 		table->n_delete++;
1150 	}
1151 
1152 	return 0;
1153 }
1154 
1155 static void
table_rollfwd1(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1156 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1157 {
1158 	struct table *table = &ctl->tables[table_id];
1159 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1160 	struct action *a;
1161 	uint8_t *action_data;
1162 	uint64_t action_id;
1163 
1164 	/* Copy the pending default entry. */
1165 	if (!table->pending_default)
1166 		return;
1167 
1168 	action_id = table->pending_default->action_id;
1169 	action_data = table->pending_default->action_data;
1170 	a = &ctl->actions[action_id];
1171 
1172 	memcpy(ts_next->default_action_data,
1173 	       action_data,
1174 	       a->data_size);
1175 
1176 	ts_next->default_action_id = action_id;
1177 }
1178 
1179 static void
table_rollfwd2(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1180 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1181 {
1182 	struct table *table = &ctl->tables[table_id];
1183 
1184 	/* Move all the pending add entries to the table, as they are now part
1185 	 * of the table.
1186 	 */
1187 	table_pending_add_admit(table);
1188 
1189 	/* Move all the pending modify1 entries to table, are they are now part
1190 	 * of the table. Free up all the pending modify0 entries, as they are no
1191 	 * longer part of the table.
1192 	 */
1193 	table_pending_modify1_admit(table);
1194 	table_pending_modify0_free(table);
1195 
1196 	/* Free up all the pending delete entries, as they are no longer part of
1197 	 * the table.
1198 	 */
1199 	table_pending_delete_free(table);
1200 
1201 	/* Free up the pending default entry, as it is now part of the table. */
1202 	table_pending_default_free(table);
1203 }
1204 
1205 static void
table_rollback(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1206 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1207 {
1208 	struct table *table = &ctl->tables[table_id];
1209 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1210 	struct rte_swx_table_entry *entry;
1211 
1212 	/* Add back all the entries that were just deleted. */
1213 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
1214 		if (!table->n_delete)
1215 			break;
1216 
1217 		table->ops.add(ts_next->obj, entry);
1218 		table->n_delete--;
1219 	}
1220 
1221 	/* Add back the old copy for all the entries that were just
1222 	 * modified.
1223 	 */
1224 	TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1225 		if (!table->n_modify)
1226 			break;
1227 
1228 		table->ops.add(ts_next->obj, entry);
1229 		table->n_modify--;
1230 	}
1231 
1232 	/* Delete all the entries that were just added. */
1233 	TAILQ_FOREACH(entry, &table->pending_add, node) {
1234 		if (!table->n_add)
1235 			break;
1236 
1237 		table->ops.del(ts_next->obj, entry);
1238 		table->n_add--;
1239 	}
1240 }
1241 
1242 static void
table_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1243 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1244 {
1245 	struct table *table = &ctl->tables[table_id];
1246 
1247 	/* Free up all the pending add entries, as none of them is part of the
1248 	 * table.
1249 	 */
1250 	table_pending_add_free(table);
1251 
1252 	/* Free up all the pending modify1 entries, as none of them made it to
1253 	 * the table. Add back all the pending modify0 entries, as none of them
1254 	 * was deleted from the table.
1255 	 */
1256 	table_pending_modify1_free(table);
1257 	table_pending_modify0_admit(table);
1258 
1259 	/* Add back all the pending delete entries, as none of them was deleted
1260 	 * from the table.
1261 	 */
1262 	table_pending_delete_admit(table);
1263 
1264 	/* Free up the pending default entry, as it is no longer going to be
1265 	 * added to the table.
1266 	 */
1267 	table_pending_default_free(table);
1268 }
1269 
1270 int
rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline * ctl,int abort_on_fail)1271 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1272 {
1273 	struct rte_swx_table_state *ts;
1274 	int status = 0;
1275 	uint32_t i;
1276 
1277 	CHECK(ctl, EINVAL);
1278 
1279 	/* Operate the changes on the current ts_next before it becomes the new
1280 	 * ts.
1281 	 */
1282 	for (i = 0; i < ctl->info.n_tables; i++) {
1283 		status = table_rollfwd0(ctl, i);
1284 		if (status)
1285 			goto rollback;
1286 	}
1287 
1288 	for (i = 0; i < ctl->info.n_tables; i++)
1289 		table_rollfwd1(ctl, i);
1290 
1291 	/* Swap the table state for the data plane. The current ts and ts_next
1292 	 * become the new ts_next and ts, respectively.
1293 	 */
1294 	rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1295 	usleep(100);
1296 	ts = ctl->ts;
1297 	ctl->ts = ctl->ts_next;
1298 	ctl->ts_next = ts;
1299 
1300 	/* Operate the changes on the current ts_next, which is the previous ts.
1301 	 */
1302 	for (i = 0; i < ctl->info.n_tables; i++) {
1303 		table_rollfwd0(ctl, i);
1304 		table_rollfwd1(ctl, i);
1305 		table_rollfwd2(ctl, i);
1306 	}
1307 
1308 	return 0;
1309 
1310 rollback:
1311 	for (i = 0; i < ctl->info.n_tables; i++) {
1312 		table_rollback(ctl, i);
1313 		if (abort_on_fail)
1314 			table_abort(ctl, i);
1315 	}
1316 
1317 	return status;
1318 }
1319 
1320 void
rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline * ctl)1321 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1322 {
1323 	uint32_t i;
1324 
1325 	if (!ctl)
1326 		return;
1327 
1328 	for (i = 0; i < ctl->info.n_tables; i++)
1329 		table_abort(ctl, i);
1330 }
1331 
1332 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1333 
1334 struct rte_swx_table_entry *
rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline * ctl,const char * table_name,const char * string)1335 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1336 				      const char *table_name,
1337 				      const char *string)
1338 {
1339 	char *tokens[RTE_SWX_CTL_ENTRY_TOKENS_MAX];
1340 	struct table *table;
1341 	struct action *action;
1342 	struct rte_swx_table_entry *entry = NULL;
1343 	char *s0 = NULL, *s;
1344 	uint32_t n_tokens = 0, arg_offset = 0, i;
1345 
1346 	/* Check input arguments. */
1347 	if (!ctl)
1348 		goto error;
1349 
1350 	if (!table_name || !table_name[0])
1351 		goto error;
1352 
1353 	table = table_find(ctl, table_name);
1354 	if (!table)
1355 		goto error;
1356 
1357 	if (!string || !string[0])
1358 		goto error;
1359 
1360 	/* Memory allocation. */
1361 	s0 = strdup(string);
1362 	if (!s0)
1363 		goto error;
1364 
1365 	entry = table_entry_alloc(table);
1366 	if (!entry)
1367 		goto error;
1368 
1369 	/* Parse the string into tokens. */
1370 	for (s = s0; ; ) {
1371 		char *token;
1372 
1373 		token = strtok_r(s, " \f\n\r\t\v", &s);
1374 		if (!token)
1375 			break;
1376 
1377 		if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1378 			goto error;
1379 
1380 		tokens[n_tokens] = token;
1381 		n_tokens++;
1382 	}
1383 
1384 	if ((n_tokens < 3 + table->info.n_match_fields) ||
1385 	    strcmp(tokens[0], "match") ||
1386 	    strcmp(tokens[1 + table->info.n_match_fields], "action"))
1387 		goto error;
1388 
1389 	action = action_find(ctl, tokens[2 + table->info.n_match_fields]);
1390 	if (!action)
1391 		goto error;
1392 
1393 	if (n_tokens != 3 + table->info.n_match_fields +
1394 	    action->info.n_args * 2)
1395 		goto error;
1396 
1397 	/*
1398 	 * Match.
1399 	 */
1400 	for (i = 0; i < table->info.n_match_fields; i++) {
1401 		struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1402 		char *mf_val = tokens[1 + i];
1403 		uint64_t val;
1404 
1405 		val = strtoull(mf_val, &mf_val, 0);
1406 		if (mf_val[0])
1407 			goto error;
1408 
1409 		/* Endianness conversion. */
1410 		if (mf->is_header)
1411 			val = field_hton(val, mf->n_bits);
1412 
1413 		/* Copy key and key_mask to entry. */
1414 		memcpy(&entry->key[(mf->offset - table->mf[0].offset) / 8],
1415 		       (uint8_t *)&val,
1416 		       mf->n_bits / 8);
1417 
1418 		/* TBD Set entry->key_mask for wildcard and LPM tables. */
1419 	}
1420 
1421 	/*
1422 	 * Action.
1423 	 */
1424 	/* action_id. */
1425 	entry->action_id = action - ctl->actions;
1426 
1427 	/* action_data. */
1428 	for (i = 0; i < action->info.n_args; i++) {
1429 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1430 		char *arg_name, *arg_val;
1431 		uint64_t val;
1432 		int is_nbo = 0;
1433 
1434 		arg_name = tokens[3 + table->info.n_match_fields + i * 2];
1435 		arg_val = tokens[3 + table->info.n_match_fields + i * 2 + 1];
1436 
1437 		if (strcmp(arg_name, arg->name) ||
1438 		    (strlen(arg_val) < 4) ||
1439 		    ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1440 		    (arg_val[1] != '(') ||
1441 		    (arg_val[strlen(arg_val) - 1] != ')'))
1442 			goto error;
1443 
1444 		if (arg_val[0] == 'N')
1445 			is_nbo = 1;
1446 
1447 		arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1448 		arg_val += 2; /* Remove the "H(" or "N(". */
1449 
1450 		val = strtoull(arg_val, &arg_val, 0);
1451 		if (arg_val[0])
1452 			goto error;
1453 
1454 		/* Endianness conversion. */
1455 		if (is_nbo)
1456 			val = field_hton(val, arg->n_bits);
1457 
1458 		/* Copy to entry. */
1459 		memcpy(&entry->action_data[arg_offset],
1460 		       (uint8_t *)&val,
1461 		       arg->n_bits / 8);
1462 
1463 		arg_offset += arg->n_bits / 8;
1464 	}
1465 
1466 	free(s0);
1467 	return entry;
1468 
1469 error:
1470 	table_entry_free(entry);
1471 	free(s0);
1472 	return NULL;
1473 }
1474 
1475 int
rte_swx_ctl_pipeline_table_fprintf(FILE * f,struct rte_swx_ctl_pipeline * ctl,const char * table_name)1476 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1477 				   struct rte_swx_ctl_pipeline *ctl,
1478 				   const char *table_name)
1479 {
1480 	struct table *table;
1481 	struct rte_swx_table_entry *entry;
1482 	uint32_t n_entries = 0, i;
1483 
1484 	if (!f || !ctl || !table_name || !table_name[0])
1485 		return -EINVAL;
1486 
1487 	table = table_find(ctl, table_name);
1488 	if (!table)
1489 		return -EINVAL;
1490 
1491 	/* Table. */
1492 	fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1493 		table->info.name,
1494 		table->params.key_size,
1495 		table->params.key_offset);
1496 
1497 	for (i = 0; i < table->params.key_size; i++)
1498 		fprintf(f, "%02x", table->params.key_mask0[i]);
1499 
1500 	fprintf(f, "], action data size %u bytes\n",
1501 		table->params.action_data_size);
1502 
1503 	/* Table entries. */
1504 	TAILQ_FOREACH(entry, &table->entries, node) {
1505 		struct action *action = &ctl->actions[entry->action_id];
1506 
1507 		fprintf(f, "match ");
1508 		for (i = 0; i < table->params.key_size; i++)
1509 			fprintf(f, "%02x", entry->key[i]);
1510 
1511 		fprintf(f, " action %s ", action->info.name);
1512 		for (i = 0; i < action->data_size; i++)
1513 			fprintf(f, "%02x", entry->action_data[i]);
1514 
1515 		fprintf(f, "\n");
1516 		n_entries++;
1517 	}
1518 
1519 	TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1520 		struct action *action = &ctl->actions[entry->action_id];
1521 
1522 		fprintf(f, "match ");
1523 		for (i = 0; i < table->params.key_size; i++)
1524 			fprintf(f, "%02x", entry->key[i]);
1525 
1526 		fprintf(f, " action %s ", action->info.name);
1527 		for (i = 0; i < action->data_size; i++)
1528 			fprintf(f, "%02x", entry->action_data[i]);
1529 
1530 		fprintf(f, "\n");
1531 		n_entries++;
1532 	}
1533 
1534 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
1535 		struct action *action = &ctl->actions[entry->action_id];
1536 
1537 		fprintf(f, "match ");
1538 		for (i = 0; i < table->params.key_size; i++)
1539 			fprintf(f, "%02x", entry->key[i]);
1540 
1541 		fprintf(f, " action %s ", action->info.name);
1542 		for (i = 0; i < action->data_size; i++)
1543 			fprintf(f, "%02x", entry->action_data[i]);
1544 
1545 		fprintf(f, "\n");
1546 		n_entries++;
1547 	}
1548 
1549 	fprintf(f, "# Table %s currently has %u entries.\n",
1550 		table_name,
1551 		n_entries);
1552 	return 0;
1553 }
1554