1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
3 */
4
5 #include <stdalign.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include <rte_common.h>
10 #include <rte_malloc.h>
11
12 #include "rte_port_in_action.h"
13
14 /**
15 * RTE_PORT_IN_ACTION_FLTR
16 */
17 static int
fltr_cfg_check(struct rte_port_in_action_fltr_config * cfg)18 fltr_cfg_check(struct rte_port_in_action_fltr_config *cfg)
19 {
20 if (cfg == NULL)
21 return -1;
22
23 return 0;
24 }
25
26 struct fltr_data {
27 uint32_t port_id;
28 };
29
30 static void
fltr_init(struct fltr_data * data,struct rte_port_in_action_fltr_config * cfg)31 fltr_init(struct fltr_data *data,
32 struct rte_port_in_action_fltr_config *cfg)
33 {
34 data->port_id = cfg->port_id;
35 }
36
37 static int
fltr_apply(struct fltr_data * data,struct rte_port_in_action_fltr_params * p)38 fltr_apply(struct fltr_data *data,
39 struct rte_port_in_action_fltr_params *p)
40 {
41 /* Check input arguments */
42 if (p == NULL)
43 return -1;
44
45 data->port_id = p->port_id;
46
47 return 0;
48 }
49
50 /**
51 * RTE_PORT_IN_ACTION_LB
52 */
53 static int
lb_cfg_check(struct rte_port_in_action_lb_config * cfg)54 lb_cfg_check(struct rte_port_in_action_lb_config *cfg)
55 {
56 if ((cfg == NULL) ||
57 (cfg->key_size < RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN) ||
58 (cfg->key_size > RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX) ||
59 (!rte_is_power_of_2(cfg->key_size)) ||
60 (cfg->f_hash == NULL))
61 return -1;
62
63 return 0;
64 }
65
66 struct lb_data {
67 uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
68 };
69
70 static void
lb_init(struct lb_data * data,struct rte_port_in_action_lb_config * cfg)71 lb_init(struct lb_data *data,
72 struct rte_port_in_action_lb_config *cfg)
73 {
74 memcpy(data->port_id, cfg->port_id, sizeof(cfg->port_id));
75 }
76
77 static int
lb_apply(struct lb_data * data,struct rte_port_in_action_lb_params * p)78 lb_apply(struct lb_data *data,
79 struct rte_port_in_action_lb_params *p)
80 {
81 /* Check input arguments */
82 if (p == NULL)
83 return -1;
84
85 memcpy(data->port_id, p->port_id, sizeof(p->port_id));
86
87 return 0;
88 }
89
90 /**
91 * Action profile
92 */
93 static int
action_valid(enum rte_port_in_action_type action)94 action_valid(enum rte_port_in_action_type action)
95 {
96 switch (action) {
97 case RTE_PORT_IN_ACTION_FLTR:
98 case RTE_PORT_IN_ACTION_LB:
99 return 1;
100 default:
101 return 0;
102 }
103 }
104
105 #define RTE_PORT_IN_ACTION_MAX 64
106
107 struct ap_config {
108 uint64_t action_mask;
109 struct rte_port_in_action_fltr_config fltr;
110 struct rte_port_in_action_lb_config lb;
111 };
112
113 static size_t
action_cfg_size(enum rte_port_in_action_type action)114 action_cfg_size(enum rte_port_in_action_type action)
115 {
116 switch (action) {
117 case RTE_PORT_IN_ACTION_FLTR:
118 return sizeof(struct rte_port_in_action_fltr_config);
119 case RTE_PORT_IN_ACTION_LB:
120 return sizeof(struct rte_port_in_action_lb_config);
121 default:
122 return 0;
123 }
124 }
125
126 static void*
action_cfg_get(struct ap_config * ap_config,enum rte_port_in_action_type type)127 action_cfg_get(struct ap_config *ap_config,
128 enum rte_port_in_action_type type)
129 {
130 switch (type) {
131 case RTE_PORT_IN_ACTION_FLTR:
132 return &ap_config->fltr;
133
134 case RTE_PORT_IN_ACTION_LB:
135 return &ap_config->lb;
136
137 default:
138 return NULL;
139 }
140 }
141
142 static void
action_cfg_set(struct ap_config * ap_config,enum rte_port_in_action_type type,void * action_cfg)143 action_cfg_set(struct ap_config *ap_config,
144 enum rte_port_in_action_type type,
145 void *action_cfg)
146 {
147 void *dst = action_cfg_get(ap_config, type);
148
149 if (dst)
150 memcpy(dst, action_cfg, action_cfg_size(type));
151
152 ap_config->action_mask |= 1LLU << type;
153 }
154
155 struct ap_data {
156 size_t offset[RTE_PORT_IN_ACTION_MAX];
157 size_t total_size;
158 };
159
160 static size_t
action_data_size(enum rte_port_in_action_type action,struct ap_config * ap_config __rte_unused)161 action_data_size(enum rte_port_in_action_type action,
162 struct ap_config *ap_config __rte_unused)
163 {
164 switch (action) {
165 case RTE_PORT_IN_ACTION_FLTR:
166 return sizeof(struct fltr_data);
167
168 case RTE_PORT_IN_ACTION_LB:
169 return sizeof(struct lb_data);
170
171 default:
172 return 0;
173 }
174 }
175
176 static void
action_data_offset_set(struct ap_data * ap_data,struct ap_config * ap_config)177 action_data_offset_set(struct ap_data *ap_data,
178 struct ap_config *ap_config)
179 {
180 uint64_t action_mask = ap_config->action_mask;
181 size_t offset;
182 uint32_t action;
183
184 memset(ap_data->offset, 0, sizeof(ap_data->offset));
185
186 offset = 0;
187 for (action = 0; action < RTE_PORT_IN_ACTION_MAX; action++)
188 if (action_mask & (1LLU << action)) {
189 ap_data->offset[action] = offset;
190 offset += action_data_size((enum rte_port_in_action_type)action,
191 ap_config);
192 }
193
194 ap_data->total_size = offset;
195 }
196
197 struct rte_port_in_action_profile {
198 struct ap_config cfg;
199 struct ap_data data;
200 int frozen;
201 };
202
203 struct rte_port_in_action_profile *
rte_port_in_action_profile_create(uint32_t socket_id)204 rte_port_in_action_profile_create(uint32_t socket_id)
205 {
206 struct rte_port_in_action_profile *ap;
207
208 /* Memory allocation */
209 ap = rte_zmalloc_socket(NULL,
210 sizeof(struct rte_port_in_action_profile),
211 RTE_CACHE_LINE_SIZE,
212 socket_id);
213 if (ap == NULL)
214 return NULL;
215
216 return ap;
217 }
218
219 int
rte_port_in_action_profile_action_register(struct rte_port_in_action_profile * profile,enum rte_port_in_action_type type,void * action_config)220 rte_port_in_action_profile_action_register(struct rte_port_in_action_profile *profile,
221 enum rte_port_in_action_type type,
222 void *action_config)
223 {
224 int status;
225
226 /* Check input arguments */
227 if ((profile == NULL) ||
228 profile->frozen ||
229 (action_valid(type) == 0) ||
230 (profile->cfg.action_mask & (1LLU << type)) ||
231 ((action_cfg_size(type) == 0) && action_config) ||
232 (action_cfg_size(type) && (action_config == NULL)))
233 return -EINVAL;
234
235 switch (type) {
236 case RTE_PORT_IN_ACTION_FLTR:
237 status = fltr_cfg_check(action_config);
238 break;
239
240 case RTE_PORT_IN_ACTION_LB:
241 status = lb_cfg_check(action_config);
242 break;
243
244 default:
245 status = 0;
246 break;
247 }
248
249 if (status)
250 return status;
251
252 /* Action enable */
253 action_cfg_set(&profile->cfg, type, action_config);
254
255 return 0;
256 }
257
258 int
rte_port_in_action_profile_freeze(struct rte_port_in_action_profile * profile)259 rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile)
260 {
261 if (profile->frozen)
262 return -EBUSY;
263
264 action_data_offset_set(&profile->data, &profile->cfg);
265 profile->frozen = 1;
266
267 return 0;
268 }
269
270 int
rte_port_in_action_profile_free(struct rte_port_in_action_profile * profile)271 rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile)
272 {
273 if (profile == NULL)
274 return 0;
275
276 free(profile);
277 return 0;
278 }
279
280 /**
281 * Action
282 */
283 struct rte_port_in_action {
284 struct ap_config cfg;
285 struct ap_data data;
286 alignas(RTE_CACHE_LINE_SIZE) uint8_t memory[];
287 };
288
289 static __rte_always_inline void *
action_data_get(struct rte_port_in_action * action,enum rte_port_in_action_type type)290 action_data_get(struct rte_port_in_action *action,
291 enum rte_port_in_action_type type)
292 {
293 size_t offset = action->data.offset[type];
294
295 return &action->memory[offset];
296 }
297
298 static void
action_data_init(struct rte_port_in_action * action,enum rte_port_in_action_type type)299 action_data_init(struct rte_port_in_action *action,
300 enum rte_port_in_action_type type)
301 {
302 void *data = action_data_get(action, type);
303
304 switch (type) {
305 case RTE_PORT_IN_ACTION_FLTR:
306 fltr_init(data, &action->cfg.fltr);
307 return;
308
309 case RTE_PORT_IN_ACTION_LB:
310 lb_init(data, &action->cfg.lb);
311 return;
312
313 default:
314 return;
315 }
316 }
317
318 struct rte_port_in_action *
rte_port_in_action_create(struct rte_port_in_action_profile * profile,uint32_t socket_id)319 rte_port_in_action_create(struct rte_port_in_action_profile *profile,
320 uint32_t socket_id)
321 {
322 struct rte_port_in_action *action;
323 size_t size;
324 uint32_t i;
325
326 /* Check input arguments */
327 if ((profile == NULL) ||
328 (profile->frozen == 0))
329 return NULL;
330
331 /* Memory allocation */
332 size = sizeof(struct rte_port_in_action) + profile->data.total_size;
333 size = RTE_CACHE_LINE_ROUNDUP(size);
334
335 action = rte_zmalloc_socket(NULL,
336 size,
337 RTE_CACHE_LINE_SIZE,
338 socket_id);
339 if (action == NULL)
340 return NULL;
341
342 /* Initialization */
343 memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
344 memcpy(&action->data, &profile->data, sizeof(profile->data));
345
346 for (i = 0; i < RTE_PORT_IN_ACTION_MAX; i++)
347 if (action->cfg.action_mask & (1LLU << i))
348 action_data_init(action,
349 (enum rte_port_in_action_type)i);
350
351 return action;
352 }
353
354 int
rte_port_in_action_apply(struct rte_port_in_action * action,enum rte_port_in_action_type type,void * action_params)355 rte_port_in_action_apply(struct rte_port_in_action *action,
356 enum rte_port_in_action_type type,
357 void *action_params)
358 {
359 void *action_data;
360
361 /* Check input arguments */
362 if ((action == NULL) ||
363 (action_valid(type) == 0) ||
364 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
365 (action_params == NULL))
366 return -EINVAL;
367
368 /* Data update */
369 action_data = action_data_get(action, type);
370
371 switch (type) {
372 case RTE_PORT_IN_ACTION_FLTR:
373 return fltr_apply(action_data,
374 action_params);
375
376 case RTE_PORT_IN_ACTION_LB:
377 return lb_apply(action_data,
378 action_params);
379
380 default:
381 return -EINVAL;
382 }
383 }
384
385 static int
ah_filter_on_match(struct rte_pipeline * p,struct rte_mbuf ** pkts,uint32_t n_pkts,void * arg)386 ah_filter_on_match(struct rte_pipeline *p,
387 struct rte_mbuf **pkts,
388 uint32_t n_pkts,
389 void *arg)
390 {
391 struct rte_port_in_action *action = arg;
392 struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
393 uint64_t *key_mask = (uint64_t *) cfg->key_mask;
394 uint64_t *key = (uint64_t *) cfg->key;
395 uint32_t key_offset = cfg->key_offset;
396 struct fltr_data *data = action_data_get(action,
397 RTE_PORT_IN_ACTION_FLTR);
398 uint32_t i;
399
400 for (i = 0; i < n_pkts; i++) {
401 struct rte_mbuf *pkt = pkts[i];
402 uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
403 key_offset);
404
405 uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
406 uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
407 uint64_t or = xor0 | xor1;
408
409 if (or == 0) {
410 rte_pipeline_ah_packet_hijack(p, 1LLU << i);
411 rte_pipeline_port_out_packet_insert(p,
412 data->port_id, pkt);
413 }
414 }
415
416 return 0;
417 }
418
419 static int
ah_filter_on_mismatch(struct rte_pipeline * p,struct rte_mbuf ** pkts,uint32_t n_pkts,void * arg)420 ah_filter_on_mismatch(struct rte_pipeline *p,
421 struct rte_mbuf **pkts,
422 uint32_t n_pkts,
423 void *arg)
424 {
425 struct rte_port_in_action *action = arg;
426 struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
427 uint64_t *key_mask = (uint64_t *) cfg->key_mask;
428 uint64_t *key = (uint64_t *) cfg->key;
429 uint32_t key_offset = cfg->key_offset;
430 struct fltr_data *data = action_data_get(action,
431 RTE_PORT_IN_ACTION_FLTR);
432 uint32_t i;
433
434 for (i = 0; i < n_pkts; i++) {
435 struct rte_mbuf *pkt = pkts[i];
436 uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
437 key_offset);
438
439 uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
440 uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
441 uint64_t or = xor0 | xor1;
442
443 if (or) {
444 rte_pipeline_ah_packet_hijack(p, 1LLU << i);
445 rte_pipeline_port_out_packet_insert(p,
446 data->port_id, pkt);
447 }
448 }
449
450 return 0;
451 }
452
453 static int
ah_lb(struct rte_pipeline * p,struct rte_mbuf ** pkts,uint32_t n_pkts,void * arg)454 ah_lb(struct rte_pipeline *p,
455 struct rte_mbuf **pkts,
456 uint32_t n_pkts,
457 void *arg)
458 {
459 struct rte_port_in_action *action = arg;
460 struct rte_port_in_action_lb_config *cfg = &action->cfg.lb;
461 struct lb_data *data = action_data_get(action, RTE_PORT_IN_ACTION_LB);
462 uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);
463 uint32_t i;
464
465 rte_pipeline_ah_packet_hijack(p, pkt_mask);
466
467 for (i = 0; i < n_pkts; i++) {
468 struct rte_mbuf *pkt = pkts[i];
469 uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(pkt,
470 cfg->key_offset);
471
472 uint64_t digest = cfg->f_hash(pkt_key,
473 cfg->key_mask,
474 cfg->key_size,
475 cfg->seed);
476 uint64_t pos = digest & (RTE_PORT_IN_ACTION_LB_TABLE_SIZE - 1);
477 uint32_t port_id = data->port_id[pos];
478
479 rte_pipeline_port_out_packet_insert(p, port_id, pkt);
480 }
481
482 return 0;
483 }
484
485 static rte_pipeline_port_in_action_handler
ah_selector(struct rte_port_in_action * action)486 ah_selector(struct rte_port_in_action *action)
487 {
488 if (action->cfg.action_mask == 0)
489 return NULL;
490
491 if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_FLTR)
492 return (action->cfg.fltr.filter_on_match) ?
493 ah_filter_on_match : ah_filter_on_mismatch;
494
495 if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_LB)
496 return ah_lb;
497
498 return NULL;
499 }
500
501 int
rte_port_in_action_params_get(struct rte_port_in_action * action,struct rte_pipeline_port_in_params * params)502 rte_port_in_action_params_get(struct rte_port_in_action *action,
503 struct rte_pipeline_port_in_params *params)
504 {
505 rte_pipeline_port_in_action_handler f_action;
506
507 /* Check input arguments */
508 if ((action == NULL) ||
509 (params == NULL))
510 return -EINVAL;
511
512 f_action = ah_selector(action);
513
514 /* Fill in params */
515 params->f_action = f_action;
516 params->arg_ah = (f_action) ? action : NULL;
517
518 return 0;
519 }
520
521 int
rte_port_in_action_free(struct rte_port_in_action * action)522 rte_port_in_action_free(struct rte_port_in_action *action)
523 {
524 if (action == NULL)
525 return 0;
526
527 rte_free(action);
528
529 return 0;
530 }
531