xref: /dpdk/examples/ipsec-secgw/flow.c (revision 72206323a5dd3182b13f61b25a64abdddfee595c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (C) 2020 Marvell International Ltd.
3  */
4 
5 #include <stdio.h>
6 
7 #include <rte_common.h>
8 #include <rte_flow.h>
9 #include <rte_ip.h>
10 
11 #include "flow.h"
12 #include "ipsec-secgw.h"
13 #include "parser.h"
14 
15 #define FLOW_RULES_MAX 128
16 
17 struct flow_rule_entry {
18 	uint8_t is_eth;
19 	uint8_t is_ipv4;
20 	uint8_t is_ipv6;
21 	RTE_STD_C11
22 	union {
23 		struct {
24 			struct rte_flow_item_ipv4 spec;
25 			struct rte_flow_item_ipv4 mask;
26 		} ipv4;
27 		struct {
28 			struct rte_flow_item_ipv6 spec;
29 			struct rte_flow_item_ipv6 mask;
30 		} ipv6;
31 	};
32 	struct rte_flow_item_mark mark_val;
33 	uint16_t port;
34 	uint16_t queue;
35 	bool is_queue_set;
36 	bool enable_count;
37 	bool enable_mark;
38 	bool set_security_action;
39 	bool set_mark_action;
40 	uint32_t mark_action_val;
41 	struct rte_flow *flow;
42 } flow_rule_tbl[FLOW_RULES_MAX];
43 
44 int nb_flow_rule;
45 
46 static void
47 ipv4_hdr_print(struct rte_ipv4_hdr *hdr)
48 {
49 	char a, b, c, d;
50 
51 	uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
52 	printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
53 
54 	uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
55 	printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d);
56 }
57 
58 static int
59 ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
60 	      struct parse_status *status)
61 {
62 	struct in_addr ip;
63 	uint32_t depth;
64 
65 	APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
66 		 "unrecognized input \"%s\", expect valid ipv4 addr", token);
67 	if (status->status < 0)
68 		return -1;
69 
70 	if (depth > 32)
71 		return -1;
72 
73 	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
74 
75 	*spec = ip.s_addr;
76 
77 	if (depth < 32)
78 		*mask = htonl(*mask << (32 - depth));
79 
80 	return 0;
81 }
82 
83 static void
84 ipv6_hdr_print(struct rte_ipv6_hdr *hdr)
85 {
86 	uint8_t *addr;
87 
88 	addr = hdr->src_addr;
89 	printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
90 	       (uint16_t)((addr[0] << 8) | addr[1]),
91 	       (uint16_t)((addr[2] << 8) | addr[3]),
92 	       (uint16_t)((addr[4] << 8) | addr[5]),
93 	       (uint16_t)((addr[6] << 8) | addr[7]),
94 	       (uint16_t)((addr[8] << 8) | addr[9]),
95 	       (uint16_t)((addr[10] << 8) | addr[11]),
96 	       (uint16_t)((addr[12] << 8) | addr[13]),
97 	       (uint16_t)((addr[14] << 8) | addr[15]));
98 
99 	addr = hdr->dst_addr;
100 	printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
101 	       (uint16_t)((addr[0] << 8) | addr[1]),
102 	       (uint16_t)((addr[2] << 8) | addr[3]),
103 	       (uint16_t)((addr[4] << 8) | addr[5]),
104 	       (uint16_t)((addr[6] << 8) | addr[7]),
105 	       (uint16_t)((addr[8] << 8) | addr[9]),
106 	       (uint16_t)((addr[10] << 8) | addr[11]),
107 	       (uint16_t)((addr[12] << 8) | addr[13]),
108 	       (uint16_t)((addr[14] << 8) | addr[15]));
109 }
110 
111 static int
112 ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
113 	      struct parse_status *status)
114 {
115 	struct in6_addr ip;
116 	uint32_t depth, i;
117 
118 	APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
119 		"unrecognized input \"%s\", expect valid ipv6 address", token);
120 	if (status->status < 0)
121 		return -1;
122 
123 	memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
124 	memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
125 
126 	for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
127 		mask[i/8] &= ~(1 << (7-i%8));
128 
129 	return 0;
130 }
131 
132 void
133 parse_flow_tokens(char **tokens, uint32_t n_tokens,
134 		  struct parse_status *status)
135 {
136 	struct flow_rule_entry *rule;
137 	uint32_t ti = 0;
138 
139 	if (nb_flow_rule >= FLOW_RULES_MAX) {
140 		printf("Too many flow rules\n");
141 		return;
142 	}
143 
144 	rule = &flow_rule_tbl[nb_flow_rule];
145 	memset(rule, 0, sizeof(*rule));
146 
147 	for (ti = 0; ti < n_tokens; ti++) {
148 		if (strcmp(tokens[ti], "mark") == 0) {
149 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
150 			if (status->status < 0)
151 				return;
152 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
153 			if (status->status < 0)
154 				return;
155 
156 			rule->mark_val.id = atoi(tokens[ti]);
157 			rule->enable_mark = true;
158 			continue;
159 		}
160 		if (strcmp(tokens[ti], "eth") == 0) {
161 			rule->is_eth = true;
162 			continue;
163 		}
164 
165 		if (strcmp(tokens[ti], "ipv4") == 0) {
166 			rule->is_ipv4 = true;
167 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
168 			if (status->status < 0)
169 				return;
170 			if (strcmp(tokens[ti], "src") == 0) {
171 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
172 				if (status->status < 0)
173 					return;
174 				if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.src_addr,
175 						  &rule->ipv4.mask.hdr.src_addr,
176 						  tokens[ti], status))
177 					return;
178 			}
179 			if (strcmp(tokens[ti], "dst") == 0) {
180 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
181 				if (status->status < 0)
182 					return;
183 				if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.dst_addr,
184 						  &rule->ipv4.mask.hdr.dst_addr,
185 						  tokens[ti], status))
186 					return;
187 			}
188 			continue;
189 		}
190 		if (strcmp(tokens[ti], "ipv6") == 0) {
191 			rule->is_ipv6 = true;
192 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
193 			if (status->status < 0)
194 				return;
195 			if (strcmp(tokens[ti], "src") == 0) {
196 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
197 				if (status->status < 0)
198 					return;
199 				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr,
200 						  rule->ipv6.mask.hdr.src_addr,
201 						  tokens[ti], status))
202 					return;
203 			}
204 			if (strcmp(tokens[ti], "dst") == 0) {
205 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
206 				if (status->status < 0)
207 					return;
208 				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
209 						  rule->ipv6.mask.hdr.dst_addr,
210 						  tokens[ti], status))
211 					return;
212 			}
213 			continue;
214 		}
215 
216 		if (strcmp(tokens[ti], "port") == 0) {
217 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
218 			if (status->status < 0)
219 				return;
220 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
221 			if (status->status < 0)
222 				return;
223 
224 			rule->port = atoi(tokens[ti]);
225 			continue;
226 		}
227 
228 		if (strcmp(tokens[ti], "queue") == 0) {
229 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
230 			if (status->status < 0)
231 				return;
232 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
233 			if (status->status < 0)
234 				return;
235 
236 			rule->queue = atoi(tokens[ti]);
237 			rule->is_queue_set = true;
238 			continue;
239 		}
240 
241 		if (strcmp(tokens[ti], "count") == 0) {
242 			rule->enable_count = true;
243 			continue;
244 		}
245 
246 		if (strcmp(tokens[ti], "security") == 0) {
247 			rule->set_security_action = true;
248 			continue;
249 		}
250 		if (strcmp(tokens[ti], "set_mark") == 0) {
251 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
252 			if (status->status < 0)
253 				return;
254 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
255 			if (status->status < 0)
256 				return;
257 
258 			rule->set_mark_action = true;
259 			rule->mark_action_val = atoi(tokens[ti]);
260 			continue;
261 		}
262 
263 		sprintf(status->parse_msg, "Unrecognized input:%s\n",
264 			tokens[ti]);
265 		status->status = -1;
266 		return;
267 	}
268 	printf("\n");
269 
270 	nb_flow_rule++;
271 }
272 
273 #define MAX_RTE_FLOW_PATTERN (4)
274 #define MAX_RTE_FLOW_ACTIONS (5)
275 
276 static void
277 flow_init_single(struct flow_rule_entry *rule)
278 {
279 	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS] = {};
280 	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN] = {};
281 	struct rte_flow_action_queue queue_action;
282 	struct rte_flow_action_mark mark_action;
283 	int ret, pattern_idx = 0, act_idx = 0;
284 	struct rte_flow_item_mark mark_mask;
285 	struct rte_flow_attr attr = {};
286 	struct rte_flow_error err = {};
287 
288 	attr.egress = 0;
289 	attr.ingress = 1;
290 
291 	if (rule->is_queue_set) {
292 		queue_action.index = rule->queue;
293 		action[act_idx].type = RTE_FLOW_ACTION_TYPE_QUEUE;
294 		action[act_idx].conf = &queue_action;
295 		act_idx++;
296 	}
297 
298 	if (rule->enable_count) {
299 		action[act_idx].type = RTE_FLOW_ACTION_TYPE_COUNT;
300 		act_idx++;
301 	}
302 
303 	if (rule->set_security_action) {
304 		action[act_idx].type = RTE_FLOW_ACTION_TYPE_SECURITY;
305 		action[act_idx].conf = NULL;
306 		act_idx++;
307 	}
308 
309 	if (rule->set_mark_action) {
310 		mark_action.id = rule->mark_action_val;
311 		action[act_idx].type = RTE_FLOW_ACTION_TYPE_MARK;
312 		action[act_idx].conf = &mark_action;
313 		act_idx++;
314 	}
315 
316 	action[act_idx].type = RTE_FLOW_ACTION_TYPE_END;
317 	action[act_idx].conf = NULL;
318 
319 	if (rule->enable_mark) {
320 		mark_mask.id = UINT32_MAX;
321 		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_MARK;
322 		pattern[pattern_idx].spec = &rule->mark_val;
323 		pattern[pattern_idx].mask = &mark_mask;
324 		pattern_idx++;
325 	}
326 
327 	if (rule->is_eth) {
328 		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ETH;
329 		pattern_idx++;
330 	}
331 
332 	if (rule->is_ipv4) {
333 		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV4;
334 		pattern[pattern_idx].spec = &rule->ipv4.spec;
335 		pattern[pattern_idx].mask = &rule->ipv4.mask;
336 		pattern_idx++;
337 	}
338 
339 	if (rule->is_ipv6) {
340 		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV6;
341 		pattern[pattern_idx].spec = &rule->ipv6.spec;
342 		pattern[pattern_idx].mask = &rule->ipv6.mask;
343 		pattern_idx++;
344 	}
345 
346 	if (rule->set_security_action) {
347 		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ESP;
348 		pattern[pattern_idx].spec = NULL;
349 		pattern[pattern_idx].mask = NULL;
350 		pattern[pattern_idx].last = NULL;
351 		pattern_idx++;
352 	}
353 
354 	pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_END;
355 
356 	ret = rte_flow_validate(rule->port, &attr, pattern, action, &err);
357 	if (ret < 0) {
358 		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
359 		rule->flow = 0;
360 		return;
361 	}
362 
363 	rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
364 	if (rule->flow == NULL)
365 		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
366 }
367 
368 void
369 flow_print_counters(void)
370 {
371 	struct rte_flow_query_count count_query;
372 	struct rte_flow_action action;
373 	struct flow_rule_entry *rule;
374 	struct rte_flow_error error;
375 	int i = 0, ret = 0;
376 
377 	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
378 
379 	for (i = 0; i < nb_flow_rule; i++) {
380 		rule = &flow_rule_tbl[i];
381 		if (!rule->flow || !rule->enable_count)
382 			continue;
383 
384 		/* Poisoning to make sure PMDs update it in case of error. */
385 		memset(&error, 0x55, sizeof(error));
386 		memset(&count_query, 0, sizeof(count_query));
387 		ret = rte_flow_query(rule->port, rule->flow, &action,
388 				     &count_query, &error);
389 		if (ret)
390 			RTE_LOG(ERR, IPSEC,
391 				"Failed to get flow counter "
392 				" for port %u, err msg: %s\n",
393 				rule->port, error.message);
394 
395 		printf("Flow #%3d:", i);
396 		if (rule->is_ipv4) {
397 			printf(" spec ipv4 ");
398 			ipv4_hdr_print(&rule->ipv4.spec.hdr);
399 		}
400 		if (rule->is_ipv6) {
401 			printf(" spec ipv6 ");
402 			ipv6_hdr_print(&rule->ipv6.spec.hdr);
403 		}
404 
405 		if (rule->set_security_action)
406 			printf(" Security action set,");
407 
408 		if (rule->enable_mark)
409 			printf(" Mark Enabled");
410 
411 		printf(" Port: %d,", rule->port);
412 		if (rule->is_queue_set)
413 			printf(" Queue: %d", rule->queue);
414 		printf(" Hits: %"PRIu64"\n", count_query.hits);
415 	}
416 }
417 
418 void
419 flow_init(void)
420 {
421 	struct flow_rule_entry *rule;
422 	int i;
423 
424 	for (i = 0; i < nb_flow_rule; i++) {
425 		rule = &flow_rule_tbl[i];
426 		flow_init_single(rule);
427 	}
428 
429 	for (i = 0; i < nb_flow_rule; i++) {
430 		rule = &flow_rule_tbl[i];
431 		printf("Flow #%3d: ", i);
432 		if (rule->is_ipv4) {
433 			printf("spec ipv4 ");
434 			ipv4_hdr_print(&rule->ipv4.spec.hdr);
435 			printf("\n");
436 			printf(" mask ipv4 ");
437 			ipv4_hdr_print(&rule->ipv4.mask.hdr);
438 		}
439 		if (rule->is_ipv6) {
440 			printf("spec ipv6 ");
441 			ipv6_hdr_print(&rule->ipv6.spec.hdr);
442 			printf("\n");
443 			printf(" mask ipv6 ");
444 			ipv6_hdr_print(&rule->ipv6.mask.hdr);
445 		}
446 
447 		if (rule->enable_mark)
448 			printf(", Mark enabled");
449 
450 		printf("\tPort: %d,", rule->port);
451 		if (rule->is_queue_set)
452 			printf(" Queue: %d,", rule->queue);
453 
454 		if (rule->set_security_action)
455 			printf(" Security action set,");
456 
457 		if (rule->set_mark_action)
458 			printf(" Mark: %d,", rule->mark_action_val);
459 
460 		if (rule->enable_count)
461 			printf(" Counter enabled,");
462 
463 		if (rule->flow == NULL)
464 			printf(" [UNSUPPORTED]");
465 		printf("\n");
466 	}
467 }
468