eal/memory: fix unused SIGBUS handler
[dpdk.git] / lib / table / rte_swx_table_wm.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <errno.h>
8
9 #include <rte_common.h>
10 #include <rte_prefetch.h>
11 #include <rte_cycles.h>
12 #include <rte_acl.h>
13
14 #include "rte_swx_table_wm.h"
15
16 #ifndef RTE_SWX_TABLE_EM_USE_HUGE_PAGES
17 #define RTE_SWX_TABLE_EM_USE_HUGE_PAGES 1
18 #endif
19
20 #if RTE_SWX_TABLE_EM_USE_HUGE_PAGES
21
22 #include <rte_malloc.h>
23
24 static void *
25 env_malloc(size_t size, size_t alignment, int numa_node)
26 {
27         return rte_zmalloc_socket(NULL, size, alignment, numa_node);
28 }
29
30 static void
31 env_free(void *start, size_t size __rte_unused)
32 {
33         rte_free(start);
34 }
35
36 #else
37
38 #include <numa.h>
39
40 static void *
41 env_malloc(size_t size, size_t alignment __rte_unused, int numa_node)
42 {
43         return numa_alloc_onnode(size, numa_node);
44 }
45
46 static void
47 env_free(void *start, size_t size)
48 {
49         numa_free(start, size);
50 }
51
52 #endif
53
54 static char *get_unique_name(void)
55 {
56         uint64_t tsc = rte_get_tsc_cycles();
57         size_t size = sizeof(uint64_t) * 2 + 1;
58         char *name = calloc(1, size);
59
60         if (!name)
61                 return NULL;
62
63         snprintf(name, size, "%016" PRIx64, tsc);
64         return name;
65 }
66
67 static uint32_t
68 count_entries(struct rte_swx_table_entry_list *entries)
69 {
70         struct rte_swx_table_entry *entry;
71         uint32_t n_entries = 0;
72
73         if (!entries)
74                 return 0;
75
76         TAILQ_FOREACH(entry, entries, node)
77                 n_entries++;
78
79         return n_entries;
80 }
81
82 static int
83 acl_table_cfg_get(struct rte_acl_config *cfg, struct rte_swx_table_params *p)
84 {
85         uint32_t byte_id = 0, field_id = 0;
86
87         /* cfg->num_categories. */
88         cfg->num_categories = 1;
89
90         /* cfg->defs and cfg->num_fields. */
91         for (byte_id = 0; byte_id < p->key_size; ) {
92                 uint32_t field_size = field_id ? 4 : 1;
93                 uint8_t byte = p->key_mask0 ? p->key_mask0[byte_id] : 0xFF;
94
95                 if (!byte) {
96                         byte_id++;
97                         continue;
98                 }
99
100                 if (field_id == RTE_ACL_MAX_FIELDS)
101                         return -1;
102
103                 cfg->defs[field_id].type = RTE_ACL_FIELD_TYPE_BITMASK;
104                 cfg->defs[field_id].size = field_size;
105                 cfg->defs[field_id].field_index = field_id;
106                 cfg->defs[field_id].input_index = field_id;
107                 cfg->defs[field_id].offset = p->key_offset + byte_id;
108
109                 field_id++;
110                 byte_id += field_size;
111         }
112
113         if (!field_id)
114                 return -1;
115
116         cfg->num_fields = field_id;
117
118         /* cfg->max_size. */
119         cfg->max_size = 0;
120
121         return 0;
122 }
123
124 static void
125 acl_table_rule_field8(uint8_t *value,
126         uint8_t *mask,
127         uint8_t *key_mask0,
128         uint8_t *key_mask,
129         uint8_t *key,
130         uint32_t offset)
131 {
132         uint8_t km0, km;
133
134         km0 = key_mask0 ? key_mask0[offset] : 0xFF;
135         km = key_mask ? key_mask[offset] : 0xFF;
136
137         *value = key[offset];
138         *mask = km0 & km;
139 }
140
141 static void
142 acl_table_rule_field32(uint32_t *value,
143         uint32_t *mask,
144         uint8_t *key_mask0,
145         uint8_t *key_mask,
146         uint8_t *key,
147         uint32_t key_size,
148         uint32_t offset)
149 {
150         uint32_t km0[4], km[4], k[4];
151         uint32_t byte_id;
152
153         /* Byte 0 = MSB, byte 3 = LSB. */
154         for (byte_id = 0; byte_id < 4; byte_id++) {
155                 if (offset + byte_id >= key_size) {
156                         km0[byte_id] = 0;
157                         km[byte_id] = 0;
158                         k[byte_id] = 0;
159                         continue;
160                 }
161
162                 km0[byte_id] = key_mask0 ? key_mask0[offset + byte_id] : 0xFF;
163                 km[byte_id] = key_mask ? key_mask[offset + byte_id] : 0xFF;
164                 k[byte_id] = key[offset + byte_id];
165         }
166
167         *value = (k[0] << 24) |
168                  (k[1] << 16) |
169                  (k[2] << 8) |
170                  k[3];
171
172         *mask = ((km[0] & km0[0]) << 24) |
173                 ((km[1] & km0[1]) << 16) |
174                 ((km[2] & km0[2]) << 8) |
175                 (km[3] & km0[3]);
176 }
177
178 RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
179
180 static struct rte_acl_rule *
181 acl_table_rules_get(struct rte_acl_config *acl_cfg,
182         struct rte_swx_table_params *p,
183         struct rte_swx_table_entry_list *entries,
184         uint32_t n_entries)
185 {
186         struct rte_swx_table_entry *entry;
187         uint8_t *memory;
188         uint32_t acl_rule_size = RTE_ACL_RULE_SZ(acl_cfg->num_fields);
189         uint32_t n_fields = acl_cfg->num_fields;
190         uint32_t rule_id;
191
192         if (!n_entries)
193                 return NULL;
194
195         memory = malloc(n_entries * acl_rule_size);
196         if (!memory)
197                 return NULL;
198
199         rule_id = 0;
200         TAILQ_FOREACH(entry, entries, node) {
201                 uint8_t *m = &memory[rule_id * acl_rule_size];
202                 struct acl_rule *acl_rule = (struct acl_rule *)m;
203                 uint32_t field_id;
204
205                 acl_rule->data.category_mask = 1;
206                 acl_rule->data.priority = RTE_ACL_MAX_PRIORITY -
207                         entry->key_priority;
208                 acl_rule->data.userdata = rule_id + 1;
209
210                 for (field_id = 0; field_id < n_fields; field_id++) {
211                         struct rte_acl_field *f = &acl_rule->field[field_id];
212                         uint32_t size = acl_cfg->defs[field_id].size;
213                         uint32_t offset = acl_cfg->defs[field_id].offset -
214                                 p->key_offset;
215
216                         if (size == 1) {
217                                 uint8_t value, mask;
218
219                                 acl_table_rule_field8(&value,
220                                                       &mask,
221                                                       p->key_mask0,
222                                                       entry->key_mask,
223                                                       entry->key,
224                                                       offset);
225
226                                 f->value.u8 = value;
227                                 f->mask_range.u8 = mask;
228                         } else {
229                                 uint32_t value, mask;
230
231                                 acl_table_rule_field32(&value,
232                                                        &mask,
233                                                        p->key_mask0,
234                                                        entry->key_mask,
235                                                        entry->key,
236                                                        p->key_size,
237                                                        offset);
238
239                                 f->value.u32 = value;
240                                 f->mask_range.u32 = mask;
241                         }
242                 }
243
244                 rule_id++;
245         }
246
247         return (struct rte_acl_rule *)memory;
248 }
249
250 /* When the table to be created has no rules, the expected behavior is to always
251  * get lookup miss for any input key. To achieve this, we add a single bogus
252  * rule to the table with the rule user data set to 0, i.e. the value returned
253  * when lookup miss takes place. Whether lookup hit (the bogus rule is hit) or
254  * miss, a user data of 0 is returned, which for the ACL library is equivalent
255  * to lookup miss.
256  */
257 static struct rte_acl_rule *
258 acl_table_rules_default_get(struct rte_acl_config *acl_cfg)
259 {
260         struct rte_acl_rule *acl_rule;
261         uint32_t acl_rule_size = RTE_ACL_RULE_SZ(acl_cfg->num_fields);
262
263         acl_rule = calloc(1, acl_rule_size);
264         if (!acl_rule)
265                 return NULL;
266
267         acl_rule->data.category_mask = 1;
268         acl_rule->data.priority = RTE_ACL_MAX_PRIORITY;
269         acl_rule->data.userdata = 0;
270
271         memset(&acl_rule[1], 0xFF, acl_rule_size - sizeof(struct rte_acl_rule));
272
273         return acl_rule;
274 }
275
276 static struct rte_acl_ctx *
277 acl_table_create(struct rte_swx_table_params *params,
278         struct rte_swx_table_entry_list *entries,
279         uint32_t n_entries,
280         int numa_node)
281 {
282         struct rte_acl_param acl_params = {0};
283         struct rte_acl_config acl_cfg = {0};
284         struct rte_acl_ctx *acl_ctx = NULL;
285         struct rte_acl_rule *acl_rules = NULL;
286         char *name = NULL;
287         int status = 0;
288
289         /* ACL config data structures. */
290         name = get_unique_name();
291         if (!name) {
292                 status = -1;
293                 goto free_resources;
294         }
295
296         status = acl_table_cfg_get(&acl_cfg, params);
297         if (status)
298                 goto free_resources;
299
300         acl_rules = n_entries ?
301                 acl_table_rules_get(&acl_cfg, params, entries, n_entries) :
302                 acl_table_rules_default_get(&acl_cfg);
303         if (!acl_rules) {
304                 status = -1;
305                 goto free_resources;
306         }
307
308         n_entries = n_entries ? n_entries : 1;
309
310         /* ACL create. */
311         acl_params.name = name;
312         acl_params.socket_id = numa_node;
313         acl_params.rule_size = RTE_ACL_RULE_SZ(acl_cfg.num_fields);
314         acl_params.max_rule_num = n_entries;
315
316         acl_ctx = rte_acl_create(&acl_params);
317         if (!acl_ctx) {
318                 status = -1;
319                 goto free_resources;
320         }
321
322         /* ACL add rules. */
323         status = rte_acl_add_rules(acl_ctx, acl_rules, n_entries);
324         if (status)
325                 goto free_resources;
326
327         /* ACL build. */
328         status = rte_acl_build(acl_ctx, &acl_cfg);
329
330 free_resources:
331         if (status && acl_ctx)
332                 rte_acl_free(acl_ctx);
333
334         free(acl_rules);
335
336         free(name);
337
338         return status ? NULL : acl_ctx;
339 }
340
341 static void
342 entry_data_copy(uint8_t *data,
343         struct rte_swx_table_entry_list *entries,
344         uint32_t n_entries,
345         uint32_t entry_data_size)
346 {
347         struct rte_swx_table_entry *entry;
348         uint32_t i = 0;
349
350         if (!n_entries)
351                 return;
352
353         TAILQ_FOREACH(entry, entries, node) {
354                 uint64_t *d = (uint64_t *)&data[i * entry_data_size];
355
356                 d[0] = entry->action_id;
357                 memcpy(&d[1], entry->action_data, entry_data_size - 8);
358
359                 i++;
360         }
361 }
362
363 struct table {
364         struct rte_acl_ctx *acl_ctx;
365         uint8_t *data;
366         size_t total_size;
367         uint32_t entry_data_size;
368 };
369
370 static void
371 table_free(void *table)
372 {
373         struct table *t = table;
374
375         if (!t)
376                 return;
377
378         if (t->acl_ctx)
379                 rte_acl_free(t->acl_ctx);
380         env_free(t, t->total_size);
381 }
382
383 static void *
384 table_create(struct rte_swx_table_params *params,
385              struct rte_swx_table_entry_list *entries,
386              const char *args __rte_unused,
387              int numa_node)
388 {
389         struct table *t = NULL;
390         size_t meta_sz, data_sz, total_size;
391         uint32_t entry_data_size;
392         uint32_t n_entries = count_entries(entries);
393
394         /* Check input arguments. */
395         if (!params || !params->key_size)
396                 goto error;
397
398         /* Memory allocation and initialization. */
399         entry_data_size = 8 + params->action_data_size;
400         meta_sz = sizeof(struct table);
401         data_sz = n_entries * entry_data_size;
402         total_size = meta_sz + data_sz;
403
404         t = env_malloc(total_size, RTE_CACHE_LINE_SIZE, numa_node);
405         if (!t)
406                 goto error;
407
408         memset(t, 0, total_size);
409         t->entry_data_size = entry_data_size;
410         t->total_size = total_size;
411         t->data = (uint8_t *)&t[1];
412
413         t->acl_ctx = acl_table_create(params, entries, n_entries, numa_node);
414         if (!t->acl_ctx)
415                 goto error;
416
417         entry_data_copy(t->data, entries, n_entries, entry_data_size);
418
419         return t;
420
421 error:
422         table_free(t);
423         return NULL;
424 }
425
426 struct mailbox {
427
428 };
429
430 static uint64_t
431 table_mailbox_size_get(void)
432 {
433         return sizeof(struct mailbox);
434 }
435
436 static int
437 table_lookup(void *table,
438              void *mailbox __rte_unused,
439              const uint8_t **key,
440              uint64_t *action_id,
441              uint8_t **action_data,
442              int *hit)
443 {
444         struct table *t = table;
445         uint8_t *data;
446         uint32_t user_data;
447
448         rte_acl_classify(t->acl_ctx, key, &user_data, 1, 1);
449         if (!user_data) {
450                 *hit = 0;
451                 return 1;
452         }
453
454         data = &t->data[(user_data - 1) * t->entry_data_size];
455         *action_id = ((uint64_t *)data)[0];
456         *action_data = &data[8];
457         *hit = 1;
458         return 1;
459 }
460
461 struct rte_swx_table_ops rte_swx_table_wildcard_match_ops = {
462         .footprint_get = NULL,
463         .mailbox_size_get = table_mailbox_size_get,
464         .create = table_create,
465         .add = NULL,
466         .del = NULL,
467         .lkp = (rte_swx_table_lookup_t)table_lookup,
468         .free = table_free,
469 };