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