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