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