xref: /dpdk/lib/pipeline/rte_port_in_action.c (revision 7917b0d38e92e8b9ec5a870415b791420e10f11a)
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
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
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
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
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
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
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
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
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*
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
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
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
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 *
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
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
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
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 *
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
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 *
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
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
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
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
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
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
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
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