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