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