1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Intel Corporation
5 #include <rte_flow_classify.h>
6 #include "rte_flow_classify_parse.h"
8 struct classify_valid_pattern {
9 enum rte_flow_item_type *items;
10 parse_filter_t parse_filter;
13 static struct classify_action action;
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,
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,
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,
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);
46 static struct classify_valid_pattern classify_supported_patterns[] = {
48 { pattern_ntuple_1, classify_parse_ntuple_filter },
49 { pattern_ntuple_2, classify_parse_ntuple_filter },
50 { pattern_ntuple_3, classify_parse_ntuple_filter },
53 struct classify_action *
54 classify_get_flow_action(void)
59 /* Find the first VOID or non-VOID item pointer */
60 const struct rte_flow_item *
61 classify_find_first_item(const struct rte_flow_item *item, bool is_void)
65 while (item->type != RTE_FLOW_ITEM_TYPE_END) {
67 is_find = item->type == RTE_FLOW_ITEM_TYPE_VOID;
69 is_find = item->type != RTE_FLOW_ITEM_TYPE_VOID;
77 /* Skip all VOID items of the pattern */
79 classify_pattern_skip_void_item(struct rte_flow_item *items,
80 const struct rte_flow_item *pattern)
82 uint32_t cpy_count = 0;
83 const struct rte_flow_item *pb = pattern, *pe = pattern;
86 /* Find a non-void item first */
87 pb = classify_find_first_item(pb, false);
88 if (pb->type == RTE_FLOW_ITEM_TYPE_END) {
93 /* Find a void item */
94 pe = classify_find_first_item(pb + 1, true);
97 rte_memcpy(items, pb, sizeof(struct rte_flow_item) * cpy_count);
101 if (pe->type == RTE_FLOW_ITEM_TYPE_END) {
106 /* Copy the END item. */
107 rte_memcpy(items, pe, sizeof(struct rte_flow_item));
110 /* Check if the pattern matches a supported item type array */
112 classify_match_pattern(enum rte_flow_item_type *item_array,
113 struct rte_flow_item *pattern)
115 struct rte_flow_item *item = pattern;
117 while ((*item_array == item->type) &&
118 (*item_array != RTE_FLOW_ITEM_TYPE_END)) {
123 return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
124 item->type == RTE_FLOW_ITEM_TYPE_END);
127 /* Find if there's parse filter function matched */
129 classify_find_parse_filter_func(struct rte_flow_item *pattern)
131 parse_filter_t parse_filter = NULL;
134 for (; i < RTE_DIM(classify_supported_patterns); i++) {
135 if (classify_match_pattern(classify_supported_patterns[i].items,
138 classify_supported_patterns[i].parse_filter;
146 #define FLOW_RULE_MIN_PRIORITY 8
147 #define FLOW_RULE_MAX_PRIORITY 0
149 #define NEXT_ITEM_OF_PATTERN(item, pattern, index)\
151 item = pattern + index;\
152 while (item->type == RTE_FLOW_ITEM_TYPE_VOID) {\
154 item = pattern + index;\
158 #define NEXT_ITEM_OF_ACTION(act, actions, index)\
160 act = actions + index;\
161 while (act->type == RTE_FLOW_ACTION_TYPE_VOID) {\
163 act = actions + index;\
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.
176 * Parse the rule to see if it is a n-tuple rule.
177 * And get the n-tuple filter info BTW.
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.
184 * The first not void action should be QUEUE.
185 * The next not void action should be END.
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
195 * other members in mask and spec should set to 0x00.
196 * item->last should be NULL.
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)
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;
222 /* the first not void item can be MAC or IPv4 */
223 NEXT_ITEM_OF_PATTERN(item, pattern, index);
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");
233 if (item->type == RTE_FLOW_ITEM_TYPE_ETH) {
234 /*Not supported last point for range*/
236 rte_flow_error_set(error, EINVAL,
237 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
239 "Not supported last point for range");
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,
248 "Not supported by ntuple filter");
251 /* check if the next not void item is IPv4 */
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,
258 "Not supported by ntuple filter");
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");
270 /*Not supported last point for range*/
272 rte_flow_error_set(error, EINVAL,
273 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
274 item, "Not supported last point for range");
279 ipv4_mask = item->mask;
281 * Only support src & dst addresses, protocol,
282 * others should be masked.
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");
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;
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;
306 /* check if the next not void item is TCP or UDP or SCTP */
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");
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");
328 /*Not supported last point for range*/
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");
338 if (item->type == RTE_FLOW_ITEM_TYPE_TCP) {
339 tcp_mask = item->mask;
342 * Only support src & dst ports, tcp flags,
343 * others should be masked.
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) {
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");
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;
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");
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;
381 * Only support src & dst ports,
382 * others should be masked.
384 if (udp_mask->hdr.dgram_len ||
385 udp_mask->hdr.dgram_cksum) {
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");
394 filter->dst_port_mask = udp_mask->hdr.dst_port;
395 filter->src_port_mask = udp_mask->hdr.src_port;
397 udp_spec = item->spec;
398 filter->dst_port = udp_spec->hdr.dst_port;
399 filter->src_port = udp_spec->hdr.src_port;
401 sctp_mask = item->mask;
404 * Only support src & dst ports,
405 * others should be masked.
407 if (sctp_mask->hdr.tag ||
408 sctp_mask->hdr.cksum) {
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");
417 filter->dst_port_mask = sctp_mask->hdr.dst_port;
418 filter->src_port_mask = sctp_mask->hdr.src_port;
420 sctp_spec = item->spec;
421 filter->dst_port = sctp_spec->hdr.dst_port;
422 filter->src_port = sctp_spec->hdr.src_port;
425 /* check if the next not void item is END */
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");
436 table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
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.");
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.");
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.");
464 filter->priority = (uint16_t)attr->priority;
465 if (attr->priority > FLOW_RULE_MIN_PRIORITY)
466 filter->priority = FLOW_RULE_MAX_PRIORITY;
472 * n-tuple only supports count and Mark,
473 * check if the first not void action is COUNT or MARK.
475 memset(&action, 0, sizeof(action));
476 NEXT_ITEM_OF_ACTION(act, actions, index);
478 case RTE_FLOW_ACTION_TYPE_COUNT:
479 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
481 memcpy(&action.act.counter, count, sizeof(action.act.counter));
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));
489 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
490 rte_flow_error_set(error, EINVAL,
491 RTE_FLOW_ERROR_TYPE_ACTION, act,
496 /* check if the next not void item is MARK or COUNT or END */
498 NEXT_ITEM_OF_ACTION(act, actions, index);
500 case RTE_FLOW_ACTION_TYPE_COUNT:
501 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
503 memcpy(&action.act.counter, count, sizeof(action.act.counter));
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));
510 case RTE_FLOW_ACTION_TYPE_END:
513 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
514 rte_flow_error_set(error, EINVAL,
515 RTE_FLOW_ERROR_TYPE_ACTION, act,
520 /* check if the next not void item is END */
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,