1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include <rte_flow_classify.h>
6 #include "rte_flow_classify_parse.h"
7 #include <rte_flow_driver.h>
8 
9 struct classify_valid_pattern {
10 	enum rte_flow_item_type *items;
11 	parse_filter_t parse_filter;
12 };
13 
14 static struct classify_action action;
15 
16 /* Pattern for IPv4 5-tuple UDP filter */
17 static enum rte_flow_item_type pattern_ntuple_1[] = {
18 	RTE_FLOW_ITEM_TYPE_ETH,
19 	RTE_FLOW_ITEM_TYPE_IPV4,
20 	RTE_FLOW_ITEM_TYPE_UDP,
21 	RTE_FLOW_ITEM_TYPE_END,
22 };
23 
24 /* Pattern for IPv4 5-tuple TCP filter */
25 static enum rte_flow_item_type pattern_ntuple_2[] = {
26 	RTE_FLOW_ITEM_TYPE_ETH,
27 	RTE_FLOW_ITEM_TYPE_IPV4,
28 	RTE_FLOW_ITEM_TYPE_TCP,
29 	RTE_FLOW_ITEM_TYPE_END,
30 };
31 
32 /* Pattern for IPv4 5-tuple SCTP filter */
33 static enum rte_flow_item_type pattern_ntuple_3[] = {
34 	RTE_FLOW_ITEM_TYPE_ETH,
35 	RTE_FLOW_ITEM_TYPE_IPV4,
36 	RTE_FLOW_ITEM_TYPE_SCTP,
37 	RTE_FLOW_ITEM_TYPE_END,
38 };
39 
40 static int
41 classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
42 			 const struct rte_flow_item pattern[],
43 			 const struct rte_flow_action actions[],
44 			 struct rte_eth_ntuple_filter *filter,
45 			 struct rte_flow_error *error);
46 
47 static struct classify_valid_pattern classify_supported_patterns[] = {
48 	/* ntuple */
49 	{ pattern_ntuple_1, classify_parse_ntuple_filter },
50 	{ pattern_ntuple_2, classify_parse_ntuple_filter },
51 	{ pattern_ntuple_3, classify_parse_ntuple_filter },
52 };
53 
54 struct classify_action *
55 classify_get_flow_action(void)
56 {
57 	return &action;
58 }
59 
60 /* Find the first VOID or non-VOID item pointer */
61 const struct rte_flow_item *
62 classify_find_first_item(const struct rte_flow_item *item, bool is_void)
63 {
64 	bool is_find;
65 
66 	while (item->type != RTE_FLOW_ITEM_TYPE_END) {
67 		if (is_void)
68 			is_find = item->type == RTE_FLOW_ITEM_TYPE_VOID;
69 		else
70 			is_find = item->type != RTE_FLOW_ITEM_TYPE_VOID;
71 		if (is_find)
72 			break;
73 		item++;
74 	}
75 	return item;
76 }
77 
78 /* Skip all VOID items of the pattern */
79 void
80 classify_pattern_skip_void_item(struct rte_flow_item *items,
81 			    const struct rte_flow_item *pattern)
82 {
83 	uint32_t cpy_count = 0;
84 	const struct rte_flow_item *pb = pattern, *pe = pattern;
85 
86 	for (;;) {
87 		/* Find a non-void item first */
88 		pb = classify_find_first_item(pb, false);
89 		if (pb->type == RTE_FLOW_ITEM_TYPE_END) {
90 			pe = pb;
91 			break;
92 		}
93 
94 		/* Find a void item */
95 		pe = classify_find_first_item(pb + 1, true);
96 
97 		cpy_count = pe - pb;
98 		rte_memcpy(items, pb, sizeof(struct rte_flow_item) * cpy_count);
99 
100 		items += cpy_count;
101 
102 		if (pe->type == RTE_FLOW_ITEM_TYPE_END) {
103 			pb = pe;
104 			break;
105 		}
106 
107 		pb = pe + 1;
108 	}
109 	/* Copy the END item. */
110 	rte_memcpy(items, pe, sizeof(struct rte_flow_item));
111 }
112 
113 /* Check if the pattern matches a supported item type array */
114 static bool
115 classify_match_pattern(enum rte_flow_item_type *item_array,
116 		   struct rte_flow_item *pattern)
117 {
118 	struct rte_flow_item *item = pattern;
119 
120 	while ((*item_array == item->type) &&
121 	       (*item_array != RTE_FLOW_ITEM_TYPE_END)) {
122 		item_array++;
123 		item++;
124 	}
125 
126 	return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
127 		item->type == RTE_FLOW_ITEM_TYPE_END);
128 }
129 
130 /* Find if there's parse filter function matched */
131 parse_filter_t
132 classify_find_parse_filter_func(struct rte_flow_item *pattern)
133 {
134 	parse_filter_t parse_filter = NULL;
135 	uint8_t i = 0;
136 
137 	for (; i < RTE_DIM(classify_supported_patterns); i++) {
138 		if (classify_match_pattern(classify_supported_patterns[i].items,
139 					pattern)) {
140 			parse_filter =
141 				classify_supported_patterns[i].parse_filter;
142 			break;
143 		}
144 	}
145 
146 	return parse_filter;
147 }
148 
149 #define FLOW_RULE_MIN_PRIORITY 8
150 #define FLOW_RULE_MAX_PRIORITY 0
151 
152 #define NEXT_ITEM_OF_PATTERN(item, pattern, index)\
153 	do {\
154 		item = pattern + index;\
155 		while (item->type == RTE_FLOW_ITEM_TYPE_VOID) {\
156 			index++;\
157 			item = pattern + index;\
158 		} \
159 	} while (0)
160 
161 #define NEXT_ITEM_OF_ACTION(act, actions, index)\
162 	do {\
163 		act = actions + index;\
164 		while (act->type == RTE_FLOW_ACTION_TYPE_VOID) {\
165 			index++;\
166 			act = actions + index;\
167 		} \
168 	} while (0)
169 
170 /**
171  * Please aware there's an assumption for all the parsers.
172  * rte_flow_item is using big endian, rte_flow_attr and
173  * rte_flow_action are using CPU order.
174  * Because the pattern is used to describe the packets,
175  * normally the packets should use network order.
176  */
177 
178 /**
179  * Parse the rule to see if it is a n-tuple rule.
180  * And get the n-tuple filter info BTW.
181  * pattern:
182  * The first not void item can be ETH or IPV4.
183  * The second not void item must be IPV4 if the first one is ETH.
184  * The third not void item must be UDP or TCP.
185  * The next not void item must be END.
186  * action:
187  * The first not void action should be QUEUE.
188  * The next not void action should be END.
189  * pattern example:
190  * ITEM		Spec			Mask
191  * ETH		NULL			NULL
192  * IPV4		src_addr 192.168.1.20	0xFFFFFFFF
193  *			dst_addr 192.167.3.50	0xFFFFFFFF
194  *			next_proto_id	17	0xFF
195  * UDP/TCP/	src_port	80	0xFFFF
196  * SCTP		dst_port	80	0xFFFF
197  * END
198  * other members in mask and spec should set to 0x00.
199  * item->last should be NULL.
200  */
201 static int
202 classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
203 			 const struct rte_flow_item pattern[],
204 			 const struct rte_flow_action actions[],
205 			 struct rte_eth_ntuple_filter *filter,
206 			 struct rte_flow_error *error)
207 {
208 	const struct rte_flow_item *item;
209 	const struct rte_flow_action *act;
210 	const struct rte_flow_item_ipv4 *ipv4_spec;
211 	const struct rte_flow_item_ipv4 *ipv4_mask;
212 	const struct rte_flow_item_tcp *tcp_spec;
213 	const struct rte_flow_item_tcp *tcp_mask;
214 	const struct rte_flow_item_udp *udp_spec;
215 	const struct rte_flow_item_udp *udp_mask;
216 	const struct rte_flow_item_sctp *sctp_spec;
217 	const struct rte_flow_item_sctp *sctp_mask;
218 	const struct rte_flow_action_count *count;
219 	const struct rte_flow_action_mark *mark_spec;
220 	uint32_t index;
221 
222 	/* parse pattern */
223 	index = 0;
224 
225 	/* the first not void item can be MAC or IPv4 */
226 	NEXT_ITEM_OF_PATTERN(item, pattern, index);
227 
228 	if (item->type != RTE_FLOW_ITEM_TYPE_ETH &&
229 	    item->type != RTE_FLOW_ITEM_TYPE_IPV4) {
230 		rte_flow_error_set(error, EINVAL,
231 			RTE_FLOW_ERROR_TYPE_ITEM,
232 			item, "Not supported by ntuple filter");
233 		return -EINVAL;
234 	}
235 	/* Skip Ethernet */
236 	if (item->type == RTE_FLOW_ITEM_TYPE_ETH) {
237 		/*Not supported last point for range*/
238 		if (item->last) {
239 			rte_flow_error_set(error, EINVAL,
240 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
241 					item,
242 					"Not supported last point for range");
243 			return -EINVAL;
244 
245 		}
246 		/* if the first item is MAC, the content should be NULL */
247 		if (item->spec || item->mask) {
248 			rte_flow_error_set(error, EINVAL,
249 					RTE_FLOW_ERROR_TYPE_ITEM,
250 					item,
251 					"Not supported by ntuple filter");
252 			return -EINVAL;
253 		}
254 		/* check if the next not void item is IPv4 */
255 		index++;
256 		NEXT_ITEM_OF_PATTERN(item, pattern, index);
257 		if (item->type != RTE_FLOW_ITEM_TYPE_IPV4) {
258 			rte_flow_error_set(error, EINVAL,
259 					RTE_FLOW_ERROR_TYPE_ITEM,
260 					item,
261 					"Not supported by ntuple filter");
262 			return -EINVAL;
263 		}
264 	}
265 
266 	/* get the IPv4 info */
267 	if (!item->spec || !item->mask) {
268 		rte_flow_error_set(error, EINVAL,
269 			RTE_FLOW_ERROR_TYPE_ITEM,
270 			item, "Invalid ntuple mask");
271 		return -EINVAL;
272 	}
273 	/*Not supported last point for range*/
274 	if (item->last) {
275 		rte_flow_error_set(error, EINVAL,
276 			RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
277 			item, "Not supported last point for range");
278 		return -EINVAL;
279 
280 	}
281 
282 	ipv4_mask = item->mask;
283 	/**
284 	 * Only support src & dst addresses, protocol,
285 	 * others should be masked.
286 	 */
287 	if (ipv4_mask->hdr.version_ihl ||
288 		ipv4_mask->hdr.type_of_service ||
289 		ipv4_mask->hdr.total_length ||
290 		ipv4_mask->hdr.packet_id ||
291 		ipv4_mask->hdr.fragment_offset ||
292 		ipv4_mask->hdr.time_to_live ||
293 		ipv4_mask->hdr.hdr_checksum) {
294 		rte_flow_error_set(error,
295 			EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
296 			item, "Not supported by ntuple filter");
297 		return -EINVAL;
298 	}
299 
300 	filter->dst_ip_mask = ipv4_mask->hdr.dst_addr;
301 	filter->src_ip_mask = ipv4_mask->hdr.src_addr;
302 	filter->proto_mask  = ipv4_mask->hdr.next_proto_id;
303 
304 	ipv4_spec = item->spec;
305 	filter->dst_ip = ipv4_spec->hdr.dst_addr;
306 	filter->src_ip = ipv4_spec->hdr.src_addr;
307 	filter->proto  = ipv4_spec->hdr.next_proto_id;
308 
309 	/* check if the next not void item is TCP or UDP or SCTP */
310 	index++;
311 	NEXT_ITEM_OF_PATTERN(item, pattern, index);
312 	if (item->type != RTE_FLOW_ITEM_TYPE_TCP &&
313 	    item->type != RTE_FLOW_ITEM_TYPE_UDP &&
314 	    item->type != RTE_FLOW_ITEM_TYPE_SCTP) {
315 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
316 		rte_flow_error_set(error, EINVAL,
317 			RTE_FLOW_ERROR_TYPE_ITEM,
318 			item, "Not supported by ntuple filter");
319 		return -EINVAL;
320 	}
321 
322 	/* get the TCP/UDP info */
323 	if (!item->spec || !item->mask) {
324 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
325 		rte_flow_error_set(error, EINVAL,
326 			RTE_FLOW_ERROR_TYPE_ITEM,
327 			item, "Invalid ntuple mask");
328 		return -EINVAL;
329 	}
330 
331 	/*Not supported last point for range*/
332 	if (item->last) {
333 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
334 		rte_flow_error_set(error, EINVAL,
335 			RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
336 			item, "Not supported last point for range");
337 		return -EINVAL;
338 
339 	}
340 
341 	if (item->type == RTE_FLOW_ITEM_TYPE_TCP) {
342 		tcp_mask = item->mask;
343 
344 		/**
345 		 * Only support src & dst ports, tcp flags,
346 		 * others should be masked.
347 		 */
348 		if (tcp_mask->hdr.sent_seq ||
349 		    tcp_mask->hdr.recv_ack ||
350 		    tcp_mask->hdr.data_off ||
351 		    tcp_mask->hdr.rx_win ||
352 		    tcp_mask->hdr.cksum ||
353 		    tcp_mask->hdr.tcp_urp) {
354 			memset(filter, 0,
355 				sizeof(struct rte_eth_ntuple_filter));
356 			rte_flow_error_set(error, EINVAL,
357 				RTE_FLOW_ERROR_TYPE_ITEM,
358 				item, "Not supported by ntuple filter");
359 			return -EINVAL;
360 		}
361 
362 		filter->dst_port_mask  = tcp_mask->hdr.dst_port;
363 		filter->src_port_mask  = tcp_mask->hdr.src_port;
364 		if (tcp_mask->hdr.tcp_flags == 0xFF) {
365 			filter->flags |= RTE_NTUPLE_FLAGS_TCP_FLAG;
366 		} else if (!tcp_mask->hdr.tcp_flags) {
367 			filter->flags &= ~RTE_NTUPLE_FLAGS_TCP_FLAG;
368 		} else {
369 			memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
370 			rte_flow_error_set(error, EINVAL,
371 				RTE_FLOW_ERROR_TYPE_ITEM,
372 				item, "Not supported by ntuple filter");
373 			return -EINVAL;
374 		}
375 
376 		tcp_spec = item->spec;
377 		filter->dst_port  = tcp_spec->hdr.dst_port;
378 		filter->src_port  = tcp_spec->hdr.src_port;
379 		filter->tcp_flags = tcp_spec->hdr.tcp_flags;
380 	} else if (item->type == RTE_FLOW_ITEM_TYPE_UDP) {
381 		udp_mask = item->mask;
382 
383 		/**
384 		 * Only support src & dst ports,
385 		 * others should be masked.
386 		 */
387 		if (udp_mask->hdr.dgram_len ||
388 		    udp_mask->hdr.dgram_cksum) {
389 			memset(filter, 0,
390 				sizeof(struct rte_eth_ntuple_filter));
391 			rte_flow_error_set(error, EINVAL,
392 				RTE_FLOW_ERROR_TYPE_ITEM,
393 				item, "Not supported by ntuple filter");
394 			return -EINVAL;
395 		}
396 
397 		filter->dst_port_mask = udp_mask->hdr.dst_port;
398 		filter->src_port_mask = udp_mask->hdr.src_port;
399 
400 		udp_spec = item->spec;
401 		filter->dst_port = udp_spec->hdr.dst_port;
402 		filter->src_port = udp_spec->hdr.src_port;
403 	} else {
404 		sctp_mask = item->mask;
405 
406 		/**
407 		 * Only support src & dst ports,
408 		 * others should be masked.
409 		 */
410 		if (sctp_mask->hdr.tag ||
411 		    sctp_mask->hdr.cksum) {
412 			memset(filter, 0,
413 				sizeof(struct rte_eth_ntuple_filter));
414 			rte_flow_error_set(error, EINVAL,
415 				RTE_FLOW_ERROR_TYPE_ITEM,
416 				item, "Not supported by ntuple filter");
417 			return -EINVAL;
418 		}
419 
420 		filter->dst_port_mask = sctp_mask->hdr.dst_port;
421 		filter->src_port_mask = sctp_mask->hdr.src_port;
422 
423 		sctp_spec = item->spec;
424 		filter->dst_port = sctp_spec->hdr.dst_port;
425 		filter->src_port = sctp_spec->hdr.src_port;
426 	}
427 
428 	/* check if the next not void item is END */
429 	index++;
430 	NEXT_ITEM_OF_PATTERN(item, pattern, index);
431 	if (item->type != RTE_FLOW_ITEM_TYPE_END) {
432 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
433 		rte_flow_error_set(error, EINVAL,
434 			RTE_FLOW_ERROR_TYPE_ITEM,
435 			item, "Not supported by ntuple filter");
436 		return -EINVAL;
437 	}
438 
439 	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
440 
441 	/* parse attr */
442 	/* must be input direction */
443 	if (!attr->ingress) {
444 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
445 		rte_flow_error_set(error, EINVAL,
446 				   RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
447 				   attr, "Only support ingress.");
448 		return -EINVAL;
449 	}
450 
451 	/* not supported */
452 	if (attr->egress) {
453 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
454 		rte_flow_error_set(error, EINVAL,
455 				   RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
456 				   attr, "Not support egress.");
457 		return -EINVAL;
458 	}
459 
460 	if (attr->priority > 0xFFFF) {
461 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
462 		rte_flow_error_set(error, EINVAL,
463 				   RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
464 				   attr, "Error priority.");
465 		return -EINVAL;
466 	}
467 	filter->priority = (uint16_t)attr->priority;
468 	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
469 		filter->priority = FLOW_RULE_MAX_PRIORITY;
470 
471 	/* parse action */
472 	index = 0;
473 
474 	/**
475 	 * n-tuple only supports count and Mark,
476 	 * check if the first not void action is COUNT or MARK.
477 	 */
478 	memset(&action, 0, sizeof(action));
479 	NEXT_ITEM_OF_ACTION(act, actions, index);
480 	switch (act->type) {
481 	case RTE_FLOW_ACTION_TYPE_COUNT:
482 		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
483 		count = act->conf;
484 		memcpy(&action.act.counter, count, sizeof(action.act.counter));
485 		break;
486 	case RTE_FLOW_ACTION_TYPE_MARK:
487 		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
488 		mark_spec = act->conf;
489 		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
490 		break;
491 	default:
492 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
493 		rte_flow_error_set(error, EINVAL,
494 		   RTE_FLOW_ERROR_TYPE_ACTION, act,
495 		   "Invalid action.");
496 		return -EINVAL;
497 	}
498 
499 	/* check if the next not void item is MARK or COUNT or END */
500 	index++;
501 	NEXT_ITEM_OF_ACTION(act, actions, index);
502 	switch (act->type) {
503 	case RTE_FLOW_ACTION_TYPE_COUNT:
504 		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
505 		count = act->conf;
506 		memcpy(&action.act.counter, count, sizeof(action.act.counter));
507 		break;
508 	case RTE_FLOW_ACTION_TYPE_MARK:
509 		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
510 		mark_spec = act->conf;
511 		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
512 		break;
513 	case RTE_FLOW_ACTION_TYPE_END:
514 		return 0;
515 	default:
516 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
517 		rte_flow_error_set(error, EINVAL,
518 		   RTE_FLOW_ERROR_TYPE_ACTION, act,
519 		   "Invalid action.");
520 		return -EINVAL;
521 	}
522 
523 	/* check if the next not void item is END */
524 	index++;
525 	NEXT_ITEM_OF_ACTION(act, actions, index);
526 	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
527 		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
528 		rte_flow_error_set(error, EINVAL,
529 		   RTE_FLOW_ERROR_TYPE_ACTION, act,
530 		   "Invalid action.");
531 		return -EINVAL;
532 	}
533 
534 	return 0;
535 }
536