Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2020 Intel Corporation
3 : : */
4 : :
5 : : #include "rte_malloc.h"
6 : : #include "igc_logs.h"
7 : : #include "igc_txrx.h"
8 : : #include "igc_filter.h"
9 : : #include "igc_flow.h"
10 : :
11 : : /*******************************************************************************
12 : : * All Supported Rule Type
13 : : *
14 : : * Notes:
15 : : * `para` or `(para)`, the para must been set
16 : : * `[para]`, the para is optional
17 : : * `([para1][para2]...)`, all paras is optional, but must one of them been set
18 : : * `para1 | para2 | ...`, only one of the paras can be set
19 : : *
20 : : * ether-type filter
21 : : * pattern: ETH(type)/END
22 : : * action: QUEUE/END
23 : : * attribute:
24 : : *
25 : : * n-tuple filter
26 : : * pattern: [ETH/]([IPv4(protocol)|IPv6(protocol)/][UDP(dst_port)|
27 : : * TCP([dst_port],[flags])|SCTP(dst_port)/])END
28 : : * action: QUEUE/END
29 : : * attribute: [priority(0-7)]
30 : : *
31 : : * SYN filter
32 : : * pattern: [ETH/][IPv4|IPv6/]TCP(flags=SYN)/END
33 : : * action: QUEUE/END
34 : : * attribute: [priority(0,1)]
35 : : *
36 : : * RSS filter
37 : : * pattern:
38 : : * action: RSS/END
39 : : * attribute:
40 : : ******************************************************************************/
41 : :
42 : : /* Structure to store all filters */
43 : : struct igc_all_filter {
44 : : struct igc_ethertype_filter ethertype;
45 : : struct igc_ntuple_filter ntuple;
46 : : struct igc_syn_filter syn;
47 : : struct igc_rss_filter rss;
48 : : uint32_t mask; /* see IGC_FILTER_MASK_* definition */
49 : : };
50 : :
51 : : #define IGC_FILTER_MASK_ETHER (1u << IGC_FILTER_TYPE_ETHERTYPE)
52 : : #define IGC_FILTER_MASK_NTUPLE (1u << IGC_FILTER_TYPE_NTUPLE)
53 : : #define IGC_FILTER_MASK_TCP_SYN (1u << IGC_FILTER_TYPE_SYN)
54 : : #define IGC_FILTER_MASK_RSS (1u << IGC_FILTER_TYPE_HASH)
55 : : #define IGC_FILTER_MASK_ALL (IGC_FILTER_MASK_ETHER | \
56 : : IGC_FILTER_MASK_NTUPLE | \
57 : : IGC_FILTER_MASK_TCP_SYN | \
58 : : IGC_FILTER_MASK_RSS)
59 : :
60 : : #define IGC_SET_FILTER_MASK(_filter, _mask_bits) \
61 : : ((_filter)->mask &= (_mask_bits))
62 : :
63 : : #define IGC_IS_ALL_BITS_SET(_val) ((_val) == (typeof(_val))~0)
64 : : #define IGC_NOT_ALL_BITS_SET(_val) ((_val) != (typeof(_val))~0)
65 : :
66 : : /* Parse rule attribute */
67 : : static int
68 : 0 : igc_parse_attribute(const struct rte_flow_attr *attr,
69 : : struct igc_all_filter *filter, struct rte_flow_error *error)
70 : : {
71 [ # # ]: 0 : if (!attr)
72 : : return 0;
73 : :
74 [ # # ]: 0 : if (attr->group)
75 : 0 : return rte_flow_error_set(error, EINVAL,
76 : : RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
77 : : "Not support");
78 : :
79 [ # # ]: 0 : if (attr->egress)
80 : 0 : return rte_flow_error_set(error, EINVAL,
81 : : RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attr,
82 : : "Not support");
83 : :
84 [ # # ]: 0 : if (attr->transfer)
85 : 0 : return rte_flow_error_set(error, EINVAL,
86 : : RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, attr,
87 : : "Not support");
88 : :
89 [ # # ]: 0 : if (!attr->ingress)
90 : 0 : return rte_flow_error_set(error, EINVAL,
91 : : RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,
92 : : "A rule must apply to ingress traffic");
93 : :
94 [ # # ]: 0 : if (attr->priority == 0)
95 : : return 0;
96 : :
97 : : /* only n-tuple and SYN filter have priority level */
98 : 0 : IGC_SET_FILTER_MASK(filter,
99 : : IGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);
100 : :
101 [ # # ]: 0 : if (IGC_IS_ALL_BITS_SET(attr->priority)) {
102 : : /* only SYN filter match this value */
103 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_TCP_SYN);
104 : 0 : filter->syn.hig_pri = 1;
105 : 0 : return 0;
106 : : }
107 : :
108 [ # # ]: 0 : if (attr->priority > IGC_NTUPLE_MAX_PRI)
109 : 0 : return rte_flow_error_set(error, EINVAL,
110 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, attr,
111 : : "Priority value is invalid.");
112 : :
113 [ # # ]: 0 : if (attr->priority > 1) {
114 : : /* only n-tuple filter match this value */
115 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
116 : :
117 : : /* get priority */
118 : 0 : filter->ntuple.tuple_info.priority = (uint8_t)attr->priority;
119 : 0 : return 0;
120 : : }
121 : :
122 : : /* get priority */
123 : 0 : filter->ntuple.tuple_info.priority = (uint8_t)attr->priority;
124 : 0 : filter->syn.hig_pri = (uint8_t)attr->priority;
125 : :
126 : 0 : return 0;
127 : : }
128 : :
129 : : /* function type of parse pattern */
130 : : typedef int (*igc_pattern_parse)(const struct rte_flow_item *,
131 : : struct igc_all_filter *, struct rte_flow_error *);
132 : :
133 : : static int igc_parse_pattern_void(__rte_unused const struct rte_flow_item *item,
134 : : __rte_unused struct igc_all_filter *filter,
135 : : __rte_unused struct rte_flow_error *error);
136 : : static int igc_parse_pattern_ether(const struct rte_flow_item *item,
137 : : struct igc_all_filter *filter, struct rte_flow_error *error);
138 : : static int igc_parse_pattern_ip(const struct rte_flow_item *item,
139 : : struct igc_all_filter *filter, struct rte_flow_error *error);
140 : : static int igc_parse_pattern_ipv6(const struct rte_flow_item *item,
141 : : struct igc_all_filter *filter, struct rte_flow_error *error);
142 : : static int igc_parse_pattern_udp(const struct rte_flow_item *item,
143 : : struct igc_all_filter *filter, struct rte_flow_error *error);
144 : : static int igc_parse_pattern_tcp(const struct rte_flow_item *item,
145 : : struct igc_all_filter *filter, struct rte_flow_error *error);
146 : :
147 : : static igc_pattern_parse pattern_parse_list[] = {
148 : : [RTE_FLOW_ITEM_TYPE_VOID] = igc_parse_pattern_void,
149 : : [RTE_FLOW_ITEM_TYPE_ETH] = igc_parse_pattern_ether,
150 : : [RTE_FLOW_ITEM_TYPE_IPV4] = igc_parse_pattern_ip,
151 : : [RTE_FLOW_ITEM_TYPE_IPV6] = igc_parse_pattern_ipv6,
152 : : [RTE_FLOW_ITEM_TYPE_UDP] = igc_parse_pattern_udp,
153 : : [RTE_FLOW_ITEM_TYPE_TCP] = igc_parse_pattern_tcp,
154 : : };
155 : :
156 : : /* Parse rule patterns */
157 : : static int
158 : 0 : igc_parse_patterns(const struct rte_flow_item patterns[],
159 : : struct igc_all_filter *filter, struct rte_flow_error *error)
160 : : {
161 : : const struct rte_flow_item *item = patterns;
162 : :
163 [ # # ]: 0 : if (item == NULL) {
164 : : /* only RSS filter match this pattern */
165 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_RSS);
166 : 0 : return 0;
167 : : }
168 : :
169 [ # # ]: 0 : for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
170 : : int ret;
171 : :
172 [ # # ]: 0 : if (item->type >= RTE_DIM(pattern_parse_list))
173 : 0 : return rte_flow_error_set(error, EINVAL,
174 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
175 : : "Not been supported");
176 : :
177 [ # # ]: 0 : if (item->last)
178 : 0 : return rte_flow_error_set(error, EINVAL,
179 : : RTE_FLOW_ERROR_TYPE_ITEM_LAST, item,
180 : : "Range not been supported");
181 : :
182 : : /* check pattern format is valid */
183 [ # # ]: 0 : if (!!item->spec ^ !!item->mask)
184 : 0 : return rte_flow_error_set(error, EINVAL,
185 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
186 : : "Format error");
187 : :
188 : : /* get the pattern type callback */
189 : 0 : igc_pattern_parse parse_func =
190 : : pattern_parse_list[item->type];
191 [ # # ]: 0 : if (!parse_func)
192 : 0 : return rte_flow_error_set(error, EINVAL,
193 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
194 : : "Not been supported");
195 : :
196 : : /* call the pattern type function */
197 : 0 : ret = parse_func(item, filter, error);
198 [ # # ]: 0 : if (ret)
199 : 0 : return ret;
200 : :
201 : : /* if no filter match the pattern */
202 [ # # ]: 0 : if (filter->mask == 0)
203 : 0 : return rte_flow_error_set(error, EINVAL,
204 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
205 : : "Not been supported");
206 : : }
207 : :
208 : : return 0;
209 : : }
210 : :
211 : : static int igc_parse_action_queue(struct rte_eth_dev *dev,
212 : : const struct rte_flow_action *act,
213 : : struct igc_all_filter *filter, struct rte_flow_error *error);
214 : : static int igc_parse_action_rss(struct rte_eth_dev *dev,
215 : : const struct rte_flow_action *act,
216 : : struct igc_all_filter *filter, struct rte_flow_error *error);
217 : :
218 : : /* Parse flow actions */
219 : : static int
220 : 0 : igc_parse_actions(struct rte_eth_dev *dev,
221 : : const struct rte_flow_action actions[],
222 : : struct igc_all_filter *filter,
223 : : struct rte_flow_error *error)
224 : : {
225 : : const struct rte_flow_action *act = actions;
226 : : int ret;
227 : :
228 [ # # ]: 0 : if (act == NULL)
229 : 0 : return rte_flow_error_set(error, EINVAL,
230 : : RTE_FLOW_ERROR_TYPE_ACTION_NUM, act,
231 : : "Action is needed");
232 : :
233 [ # # ]: 0 : for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
234 [ # # # # ]: 0 : switch (act->type) {
235 : 0 : case RTE_FLOW_ACTION_TYPE_QUEUE:
236 : 0 : ret = igc_parse_action_queue(dev, act, filter, error);
237 [ # # ]: 0 : if (ret)
238 : 0 : return ret;
239 : : break;
240 : 0 : case RTE_FLOW_ACTION_TYPE_RSS:
241 : 0 : ret = igc_parse_action_rss(dev, act, filter, error);
242 [ # # ]: 0 : if (ret)
243 : 0 : return ret;
244 : : break;
245 : : case RTE_FLOW_ACTION_TYPE_VOID:
246 : : break;
247 : 0 : default:
248 : 0 : return rte_flow_error_set(error, EINVAL,
249 : : RTE_FLOW_ERROR_TYPE_ACTION, act,
250 : : "Not been supported");
251 : : }
252 : :
253 : : /* if no filter match the action */
254 [ # # ]: 0 : if (filter->mask == 0)
255 : 0 : return rte_flow_error_set(error, EINVAL,
256 : : RTE_FLOW_ERROR_TYPE_ACTION, act,
257 : : "Not been supported");
258 : : }
259 : :
260 : : return 0;
261 : : }
262 : :
263 : : /* Parse a flow rule */
264 : : static int
265 : 0 : igc_parse_flow(struct rte_eth_dev *dev,
266 : : const struct rte_flow_attr *attr,
267 : : const struct rte_flow_item patterns[],
268 : : const struct rte_flow_action actions[],
269 : : struct rte_flow_error *error,
270 : : struct igc_all_filter *filter)
271 : : {
272 : : int ret;
273 : :
274 : : /* clear all filters */
275 : : memset(filter, 0, sizeof(*filter));
276 : :
277 : : /* set default filter mask */
278 : 0 : filter->mask = IGC_FILTER_MASK_ALL;
279 : :
280 : 0 : ret = igc_parse_attribute(attr, filter, error);
281 [ # # ]: 0 : if (ret)
282 : : return ret;
283 : :
284 : 0 : ret = igc_parse_patterns(patterns, filter, error);
285 [ # # ]: 0 : if (ret)
286 : : return ret;
287 : :
288 : 0 : ret = igc_parse_actions(dev, actions, filter, error);
289 [ # # ]: 0 : if (ret)
290 : : return ret;
291 : :
292 : : /* if no or more than one filter matched this flow */
293 [ # # # # ]: 0 : if (filter->mask == 0 || (filter->mask & (filter->mask - 1)))
294 : 0 : return rte_flow_error_set(error, EINVAL,
295 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
296 : : "Flow can't be recognized");
297 : : return 0;
298 : : }
299 : :
300 : : /* Parse pattern type of void */
301 : : static int
302 : 0 : igc_parse_pattern_void(__rte_unused const struct rte_flow_item *item,
303 : : __rte_unused struct igc_all_filter *filter,
304 : : __rte_unused struct rte_flow_error *error)
305 : : {
306 : 0 : return 0;
307 : : }
308 : :
309 : : /* Parse pattern type of ethernet header */
310 : : static int
311 : 0 : igc_parse_pattern_ether(const struct rte_flow_item *item,
312 : : struct igc_all_filter *filter,
313 : : struct rte_flow_error *error)
314 : : {
315 : 0 : const struct rte_flow_item_eth *spec = item->spec;
316 : 0 : const struct rte_flow_item_eth *mask = item->mask;
317 : : struct igc_ethertype_filter *ether;
318 : :
319 [ # # ]: 0 : if (mask == NULL) {
320 : : /* only n-tuple and SYN filter match the pattern */
321 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE |
322 : : IGC_FILTER_MASK_TCP_SYN);
323 : 0 : return 0;
324 : : }
325 : :
326 : : /* only ether-type filter match the pattern*/
327 [ # # ]: 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_ETHER);
328 : :
329 : : /* destination and source MAC address are not supported */
330 [ # # # # ]: 0 : if (!rte_is_zero_ether_addr(&mask->hdr.src_addr) ||
331 : : !rte_is_zero_ether_addr(&mask->hdr.dst_addr))
332 : 0 : return rte_flow_error_set(error, EINVAL,
333 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
334 : : "Only support ether-type");
335 : :
336 : : /* ether-type mask bits must be all 1 */
337 [ # # ]: 0 : if (IGC_NOT_ALL_BITS_SET(mask->hdr.ether_type))
338 : 0 : return rte_flow_error_set(error, EINVAL,
339 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
340 : : "Ethernet type mask bits must be all 1");
341 : :
342 : : ether = &filter->ethertype;
343 : :
344 : : /* get ether-type */
345 [ # # ]: 0 : ether->ether_type = rte_be_to_cpu_16(spec->hdr.ether_type);
346 : :
347 : : /* ether-type should not be IPv4 and IPv6 */
348 [ # # ]: 0 : if (ether->ether_type == RTE_ETHER_TYPE_IPV4 ||
349 [ # # ]: 0 : ether->ether_type == RTE_ETHER_TYPE_IPV6 ||
350 : : ether->ether_type == 0)
351 : 0 : return rte_flow_error_set(error, EINVAL,
352 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
353 : : "IPv4/IPv6/0 not supported by ethertype filter");
354 : : return 0;
355 : : }
356 : :
357 : : /* Parse pattern type of IP */
358 : : static int
359 : 0 : igc_parse_pattern_ip(const struct rte_flow_item *item,
360 : : struct igc_all_filter *filter,
361 : : struct rte_flow_error *error)
362 : : {
363 : 0 : const struct rte_flow_item_ipv4 *spec = item->spec;
364 : 0 : const struct rte_flow_item_ipv4 *mask = item->mask;
365 : :
366 [ # # ]: 0 : if (mask == NULL) {
367 : : /* only n-tuple and SYN filter match this pattern */
368 : 0 : IGC_SET_FILTER_MASK(filter,
369 : : IGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);
370 : 0 : return 0;
371 : : }
372 : :
373 : : /* only n-tuple filter match this pattern */
374 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
375 : :
376 : : /* only protocol is used */
377 [ # # ]: 0 : if (mask->hdr.version_ihl ||
378 : 0 : mask->hdr.type_of_service ||
379 [ # # ]: 0 : mask->hdr.total_length ||
380 [ # # ]: 0 : mask->hdr.packet_id ||
381 [ # # ]: 0 : mask->hdr.fragment_offset ||
382 [ # # ]: 0 : mask->hdr.time_to_live ||
383 [ # # ]: 0 : mask->hdr.hdr_checksum ||
384 [ # # ]: 0 : mask->hdr.dst_addr ||
385 [ # # ]: 0 : mask->hdr.src_addr)
386 : 0 : return rte_flow_error_set(error,
387 : : EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
388 : : "IPv4 only support protocol");
389 : :
390 [ # # ]: 0 : if (mask->hdr.next_proto_id == 0)
391 : : return 0;
392 : :
393 [ # # ]: 0 : if (IGC_NOT_ALL_BITS_SET(mask->hdr.next_proto_id))
394 : 0 : return rte_flow_error_set(error,
395 : : EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
396 : : "IPv4 protocol mask bits must be all 0 or 1");
397 : :
398 : : /* get protocol type */
399 : 0 : filter->ntuple.tuple_info.proto_mask = 1;
400 : 0 : filter->ntuple.tuple_info.proto = spec->hdr.next_proto_id;
401 : 0 : return 0;
402 : : }
403 : :
404 : : /*
405 : : * Check ipv6 address is 0
406 : : * Return 1 if true, 0 for false.
407 : : */
408 : : static inline bool
409 : : igc_is_zero_ipv6_addr(const void *ipv6_addr)
410 : : {
411 : : const uint64_t *ddw = ipv6_addr;
412 [ # # # # : 0 : return ddw[0] == 0 && ddw[1] == 0;
# # # # ]
413 : : }
414 : :
415 : : /* Parse pattern type of IPv6 */
416 : : static int
417 : 0 : igc_parse_pattern_ipv6(const struct rte_flow_item *item,
418 : : struct igc_all_filter *filter,
419 : : struct rte_flow_error *error)
420 : : {
421 : 0 : const struct rte_flow_item_ipv6 *spec = item->spec;
422 : 0 : const struct rte_flow_item_ipv6 *mask = item->mask;
423 : :
424 [ # # ]: 0 : if (mask == NULL) {
425 : : /* only n-tuple and syn filter match this pattern */
426 : 0 : IGC_SET_FILTER_MASK(filter,
427 : : IGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);
428 : 0 : return 0;
429 : : }
430 : :
431 : : /* only n-tuple filter match this pattern */
432 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
433 : :
434 : : /* only protocol is used */
435 [ # # ]: 0 : if (mask->hdr.vtc_flow ||
436 [ # # ]: 0 : mask->hdr.payload_len ||
437 [ # # ]: 0 : mask->hdr.hop_limits ||
438 [ # # ]: 0 : !igc_is_zero_ipv6_addr(&mask->hdr.src_addr) ||
439 : : !igc_is_zero_ipv6_addr(&mask->hdr.dst_addr))
440 : 0 : return rte_flow_error_set(error, EINVAL,
441 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
442 : : "IPv6 only support protocol");
443 : :
444 [ # # ]: 0 : if (mask->hdr.proto == 0)
445 : : return 0;
446 : :
447 [ # # ]: 0 : if (IGC_NOT_ALL_BITS_SET(mask->hdr.proto))
448 : 0 : return rte_flow_error_set(error,
449 : : EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
450 : : "IPv6 protocol mask bits must be all 0 or 1");
451 : :
452 : : /* get protocol type */
453 : 0 : filter->ntuple.tuple_info.proto_mask = 1;
454 : 0 : filter->ntuple.tuple_info.proto = spec->hdr.proto;
455 : :
456 : 0 : return 0;
457 : : }
458 : :
459 : : /* Parse pattern type of UDP */
460 : : static int
461 : 0 : igc_parse_pattern_udp(const struct rte_flow_item *item,
462 : : struct igc_all_filter *filter,
463 : : struct rte_flow_error *error)
464 : : {
465 : 0 : const struct rte_flow_item_udp *spec = item->spec;
466 : 0 : const struct rte_flow_item_udp *mask = item->mask;
467 : :
468 : : /* only n-tuple filter match this pattern */
469 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
470 : :
471 [ # # ]: 0 : if (mask == NULL)
472 : : return 0;
473 : :
474 : : /* only destination port is used */
475 [ # # # # : 0 : if (mask->hdr.dgram_len || mask->hdr.dgram_cksum || mask->hdr.src_port)
# # ]
476 : 0 : return rte_flow_error_set(error, EINVAL,
477 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
478 : : "UDP only support destination port");
479 : :
480 [ # # ]: 0 : if (mask->hdr.dst_port == 0)
481 : : return 0;
482 : :
483 [ # # ]: 0 : if (IGC_NOT_ALL_BITS_SET(mask->hdr.dst_port))
484 : 0 : return rte_flow_error_set(error, EINVAL,
485 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
486 : : "UDP port mask bits must be all 0 or 1");
487 : :
488 : : /* get destination port info. */
489 : 0 : filter->ntuple.tuple_info.dst_port_mask = 1;
490 : 0 : filter->ntuple.tuple_info.dst_port = spec->hdr.dst_port;
491 : :
492 : 0 : return 0;
493 : : }
494 : :
495 : : /* Parse pattern type of TCP */
496 : : static int
497 : 0 : igc_parse_pattern_tcp(const struct rte_flow_item *item,
498 : : struct igc_all_filter *filter,
499 : : struct rte_flow_error *error)
500 : : {
501 : 0 : const struct rte_flow_item_tcp *spec = item->spec;
502 : 0 : const struct rte_flow_item_tcp *mask = item->mask;
503 : : struct igc_ntuple_info *tuple_info = &filter->ntuple.tuple_info;
504 : :
505 [ # # ]: 0 : if (mask == NULL) {
506 : : /* only n-tuple filter match this pattern */
507 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
508 : 0 : return 0;
509 : : }
510 : :
511 : : /* only n-tuple and SYN filter match this pattern */
512 : 0 : IGC_SET_FILTER_MASK(filter,
513 : : IGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);
514 : :
515 : : /* only destination port and TCP flags are used */
516 [ # # ]: 0 : if (mask->hdr.sent_seq ||
517 [ # # ]: 0 : mask->hdr.recv_ack ||
518 [ # # ]: 0 : mask->hdr.data_off ||
519 [ # # ]: 0 : mask->hdr.rx_win ||
520 [ # # ]: 0 : mask->hdr.cksum ||
521 [ # # ]: 0 : mask->hdr.tcp_urp ||
522 [ # # ]: 0 : mask->hdr.src_port)
523 : 0 : return rte_flow_error_set(error, EINVAL,
524 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
525 : : "TCP only support destination port and flags");
526 : :
527 : : /* if destination port is used */
528 [ # # ]: 0 : if (mask->hdr.dst_port) {
529 : : /* only n-tuple match this pattern */
530 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
531 : :
532 [ # # ]: 0 : if (IGC_NOT_ALL_BITS_SET(mask->hdr.dst_port))
533 : 0 : return rte_flow_error_set(error, EINVAL,
534 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
535 : : "TCP port mask bits must be all 1");
536 : :
537 : : /* get destination port info. */
538 : 0 : tuple_info->dst_port = spec->hdr.dst_port;
539 : 0 : tuple_info->dst_port_mask = 1;
540 : : }
541 : :
542 : : /* if TCP flags are used */
543 [ # # ]: 0 : if (mask->hdr.tcp_flags) {
544 [ # # ]: 0 : if (IGC_IS_ALL_BITS_SET(mask->hdr.tcp_flags)) {
545 : : /* only n-tuple match this pattern */
546 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
547 : :
548 : : /* get TCP flags */
549 : 0 : tuple_info->tcp_flags = spec->hdr.tcp_flags;
550 [ # # ]: 0 : } else if (mask->hdr.tcp_flags == RTE_TCP_SYN_FLAG) {
551 : : /* only TCP SYN filter match this pattern */
552 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_TCP_SYN);
553 : : } else {
554 : : /* no filter match this pattern */
555 : 0 : return rte_flow_error_set(error, EINVAL,
556 : : RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,
557 : : "TCP flags can't match");
558 : : }
559 : : } else {
560 : : /* only n-tuple match this pattern */
561 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);
562 : : }
563 : :
564 : : return 0;
565 : : }
566 : :
567 : : static int
568 : 0 : igc_parse_action_queue(struct rte_eth_dev *dev,
569 : : const struct rte_flow_action *act,
570 : : struct igc_all_filter *filter,
571 : : struct rte_flow_error *error)
572 : : {
573 : : uint16_t queue_idx;
574 : :
575 [ # # ]: 0 : if (act->conf == NULL)
576 : 0 : return rte_flow_error_set(error, EINVAL,
577 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
578 : : "NULL pointer");
579 : :
580 : : /* only ether-type, n-tuple, SYN filter match the action */
581 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_ETHER |
582 : : IGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);
583 : :
584 : : /* get queue index */
585 : 0 : queue_idx = ((const struct rte_flow_action_queue *)act->conf)->index;
586 : :
587 : : /* check the queue index is valid */
588 [ # # ]: 0 : if (queue_idx >= dev->data->nb_rx_queues)
589 : 0 : return rte_flow_error_set(error, EINVAL,
590 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
591 : : "Queue id is invalid");
592 : :
593 : : /* get queue info. */
594 : 0 : filter->ethertype.queue = queue_idx;
595 : 0 : filter->ntuple.queue = queue_idx;
596 : 0 : filter->syn.queue = queue_idx;
597 : 0 : return 0;
598 : : }
599 : :
600 : : /* Parse action of RSS */
601 : : static int
602 : 0 : igc_parse_action_rss(struct rte_eth_dev *dev,
603 : : const struct rte_flow_action *act,
604 : : struct igc_all_filter *filter,
605 : : struct rte_flow_error *error)
606 : : {
607 : 0 : const struct rte_flow_action_rss *rss = act->conf;
608 : : uint32_t i;
609 : :
610 [ # # ]: 0 : if (act->conf == NULL)
611 : 0 : return rte_flow_error_set(error, EINVAL,
612 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
613 : : "NULL pointer");
614 : :
615 : : /* only RSS match the action */
616 : 0 : IGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_RSS);
617 : :
618 : : /* RSS redirect table can't be zero and can't exceed 128 */
619 [ # # # # ]: 0 : if (!rss || !rss->queue_num || rss->queue_num > IGC_RSS_RDT_SIZD)
620 : 0 : return rte_flow_error_set(error, EINVAL,
621 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
622 : : "No valid queues");
623 : :
624 : : /* queue index can't exceed max queue index */
625 [ # # ]: 0 : for (i = 0; i < rss->queue_num; i++) {
626 [ # # ]: 0 : if (rss->queue[i] >= dev->data->nb_rx_queues)
627 : 0 : return rte_flow_error_set(error, EINVAL,
628 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
629 : : "Queue id is invalid");
630 : : }
631 : :
632 : : /* only default RSS hash function is supported */
633 [ # # ]: 0 : if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
634 : 0 : return rte_flow_error_set(error, ENOTSUP,
635 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
636 : : "Only default RSS hash functions is supported");
637 : :
638 [ # # ]: 0 : if (rss->level)
639 : 0 : return rte_flow_error_set(error, ENOTSUP,
640 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
641 : : "Only 0 RSS encapsulation level is supported");
642 : :
643 : : /* check key length is valid */
644 [ # # ]: 0 : if (rss->key_len && rss->key_len != sizeof(filter->rss.key))
645 : 0 : return rte_flow_error_set(error, ENOTSUP,
646 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
647 : : "RSS hash key must be exactly 40 bytes");
648 : :
649 : : /* get RSS info. */
650 : 0 : igc_rss_conf_set(&filter->rss, rss);
651 : 0 : return 0;
652 : : }
653 : :
654 : : /**
655 : : * Allocate a rte_flow from the heap
656 : : * Return the pointer of the flow, or NULL for failed
657 : : **/
658 : : static inline struct rte_flow *
659 : 0 : igc_alloc_flow(const void *filter, enum igc_filter_type type, size_t inbytes)
660 : : {
661 : : /* allocate memory, 8 bytes boundary aligned */
662 : 0 : struct rte_flow *flow = rte_malloc("igc flow filter",
663 : : sizeof(struct rte_flow) + inbytes, 8);
664 [ # # ]: 0 : if (flow == NULL) {
665 : 0 : PMD_DRV_LOG(ERR, "failed to allocate memory");
666 : 0 : return NULL;
667 : : }
668 : :
669 : 0 : flow->filter_type = type;
670 : :
671 : : /* copy filter data */
672 : 0 : memcpy(flow->filter, filter, inbytes);
673 : 0 : return flow;
674 : : }
675 : :
676 : : /* Append a rte_flow to the list */
677 : : static inline void
678 : : igc_append_flow(struct igc_flow_list *list, struct rte_flow *flow)
679 : : {
680 : 0 : TAILQ_INSERT_TAIL(list, flow, node);
681 : : }
682 : :
683 : : /**
684 : : * Remove the flow and free the flow buffer
685 : : * The caller should make sure the flow is really exist in the list
686 : : **/
687 : : static inline void
688 : : igc_remove_flow(struct igc_flow_list *list, struct rte_flow *flow)
689 : : {
690 [ # # # # ]: 0 : TAILQ_REMOVE(list, flow, node);
691 : 0 : rte_free(flow);
692 : 0 : }
693 : :
694 : : /* Check whether the flow is really in the list or not */
695 : : static inline bool
696 : : igc_is_flow_in_list(struct igc_flow_list *list, struct rte_flow *flow)
697 : : {
698 : : struct rte_flow *it;
699 : :
700 [ # # ]: 0 : TAILQ_FOREACH(it, list, node) {
701 [ # # ]: 0 : if (it == flow)
702 : : return true;
703 : : }
704 : :
705 : : return false;
706 : : }
707 : :
708 : : /**
709 : : * Create a flow rule.
710 : : * Theoretically one rule can match more than one filters.
711 : : * We will let it use the filter which it hit first.
712 : : * So, the sequence matters.
713 : : **/
714 : : static struct rte_flow *
715 : 0 : igc_flow_create(struct rte_eth_dev *dev,
716 : : const struct rte_flow_attr *attr,
717 : : const struct rte_flow_item patterns[],
718 : : const struct rte_flow_action actions[],
719 : : struct rte_flow_error *error)
720 : : {
721 : : struct rte_flow *flow = NULL;
722 : : struct igc_all_filter filter;
723 : : int ret;
724 : :
725 : 0 : ret = igc_parse_flow(dev, attr, patterns, actions, error, &filter);
726 [ # # ]: 0 : if (ret)
727 : : return NULL;
728 : : ret = -ENOMEM;
729 : :
730 [ # # # # : 0 : switch (filter.mask) {
# ]
731 : 0 : case IGC_FILTER_MASK_ETHER:
732 : 0 : flow = igc_alloc_flow(&filter.ethertype,
733 : : IGC_FILTER_TYPE_ETHERTYPE,
734 : : sizeof(filter.ethertype));
735 [ # # ]: 0 : if (flow)
736 : 0 : ret = igc_add_ethertype_filter(dev, &filter.ethertype);
737 : : break;
738 : 0 : case IGC_FILTER_MASK_NTUPLE:
739 : : /* Check n-tuple filter is valid */
740 [ # # ]: 0 : if (filter.ntuple.tuple_info.dst_port_mask == 0 &&
741 : : filter.ntuple.tuple_info.proto_mask == 0) {
742 : 0 : rte_flow_error_set(error, EINVAL,
743 : : RTE_FLOW_ERROR_TYPE_NONE, NULL,
744 : : "Flow can't be recognized");
745 : 0 : return NULL;
746 : : }
747 : :
748 : 0 : flow = igc_alloc_flow(&filter.ntuple, IGC_FILTER_TYPE_NTUPLE,
749 : : sizeof(filter.ntuple));
750 [ # # ]: 0 : if (flow)
751 : 0 : ret = igc_add_ntuple_filter(dev, &filter.ntuple);
752 : : break;
753 : 0 : case IGC_FILTER_MASK_TCP_SYN:
754 : 0 : flow = igc_alloc_flow(&filter.syn, IGC_FILTER_TYPE_SYN,
755 : : sizeof(filter.syn));
756 [ # # ]: 0 : if (flow)
757 : 0 : ret = igc_set_syn_filter(dev, &filter.syn);
758 : : break;
759 : 0 : case IGC_FILTER_MASK_RSS:
760 : 0 : flow = igc_alloc_flow(&filter.rss, IGC_FILTER_TYPE_HASH,
761 : : sizeof(filter.rss));
762 [ # # ]: 0 : if (flow) {
763 : : struct igc_rss_filter *rss =
764 : : (struct igc_rss_filter *)flow->filter;
765 : 0 : rss->conf.key = rss->key;
766 : 0 : rss->conf.queue = rss->queue;
767 : 0 : ret = igc_add_rss_filter(dev, &filter.rss);
768 : : }
769 : : break;
770 : 0 : default:
771 : 0 : rte_flow_error_set(error, EINVAL,
772 : : RTE_FLOW_ERROR_TYPE_NONE, NULL,
773 : : "Flow can't be recognized");
774 : 0 : return NULL;
775 : : }
776 : :
777 [ # # ]: 0 : if (ret) {
778 : 0 : rte_free(flow);
779 : 0 : rte_flow_error_set(error, -ret,
780 : : RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
781 : : "Failed to create flow.");
782 : 0 : return NULL;
783 : : }
784 : :
785 : : /* append the flow to the tail of the list */
786 : 0 : igc_append_flow(IGC_DEV_PRIVATE_FLOW_LIST(dev), flow);
787 : 0 : return flow;
788 : : }
789 : :
790 : : /**
791 : : * Check if the flow rule is supported by the device.
792 : : * It only checks the format. Don't guarantee the rule can be programmed into
793 : : * the HW. Because there can be no enough room for the rule.
794 : : **/
795 : : static int
796 : 0 : igc_flow_validate(struct rte_eth_dev *dev,
797 : : const struct rte_flow_attr *attr,
798 : : const struct rte_flow_item patterns[],
799 : : const struct rte_flow_action actions[],
800 : : struct rte_flow_error *error)
801 : : {
802 : : struct igc_all_filter filter;
803 : : int ret;
804 : :
805 : 0 : ret = igc_parse_flow(dev, attr, patterns, actions, error, &filter);
806 [ # # ]: 0 : if (ret)
807 : : return ret;
808 : :
809 [ # # ]: 0 : switch (filter.mask) {
810 : 0 : case IGC_FILTER_MASK_NTUPLE:
811 : : /* Check n-tuple filter is valid */
812 [ # # ]: 0 : if (filter.ntuple.tuple_info.dst_port_mask == 0 &&
813 : : filter.ntuple.tuple_info.proto_mask == 0)
814 : 0 : return rte_flow_error_set(error, EINVAL,
815 : : RTE_FLOW_ERROR_TYPE_NONE, NULL,
816 : : "Flow can't be recognized");
817 : : break;
818 : : }
819 : :
820 : : return 0;
821 : : }
822 : :
823 : : /**
824 : : * Disable a valid flow, the flow must be not NULL and
825 : : * chained in the device flow list.
826 : : **/
827 : : static int
828 : 0 : igc_disable_flow(struct rte_eth_dev *dev, struct rte_flow *flow)
829 : : {
830 : : int ret = 0;
831 : :
832 [ # # # # : 0 : switch (flow->filter_type) {
# ]
833 : 0 : case IGC_FILTER_TYPE_ETHERTYPE:
834 : 0 : ret = igc_del_ethertype_filter(dev,
835 : 0 : (struct igc_ethertype_filter *)&flow->filter);
836 : 0 : break;
837 : 0 : case IGC_FILTER_TYPE_NTUPLE:
838 : 0 : ret = igc_del_ntuple_filter(dev,
839 : 0 : (struct igc_ntuple_filter *)&flow->filter);
840 : 0 : break;
841 : 0 : case IGC_FILTER_TYPE_SYN:
842 : 0 : igc_clear_syn_filter(dev);
843 : 0 : break;
844 : 0 : case IGC_FILTER_TYPE_HASH:
845 : 0 : ret = igc_del_rss_filter(dev);
846 : 0 : break;
847 : 0 : default:
848 : 0 : PMD_DRV_LOG(ERR, "Filter type (%d) not supported",
849 : : flow->filter_type);
850 : : ret = -EINVAL;
851 : : }
852 : :
853 : 0 : return ret;
854 : : }
855 : :
856 : : /* Destroy a flow rule */
857 : : static int
858 : 0 : igc_flow_destroy(struct rte_eth_dev *dev,
859 : : struct rte_flow *flow,
860 : : struct rte_flow_error *error)
861 : : {
862 : 0 : struct igc_flow_list *list = IGC_DEV_PRIVATE_FLOW_LIST(dev);
863 : : int ret;
864 : :
865 [ # # ]: 0 : if (!flow) {
866 : 0 : PMD_DRV_LOG(ERR, "NULL flow!");
867 : 0 : return -EINVAL;
868 : : }
869 : :
870 : : /* check the flow is create by IGC PMD */
871 [ # # ]: 0 : if (!igc_is_flow_in_list(list, flow)) {
872 : 0 : PMD_DRV_LOG(ERR, "Flow(%p) not been found!", flow);
873 : 0 : return -ENOENT;
874 : : }
875 : :
876 : 0 : ret = igc_disable_flow(dev, flow);
877 [ # # ]: 0 : if (ret)
878 : 0 : rte_flow_error_set(error, -ret,
879 : : RTE_FLOW_ERROR_TYPE_HANDLE,
880 : : NULL, "Failed to destroy flow");
881 : :
882 : : igc_remove_flow(list, flow);
883 : 0 : return ret;
884 : : }
885 : :
886 : : /* Initiate device flow list header */
887 : : void
888 : 0 : igc_flow_init(struct rte_eth_dev *dev)
889 : : {
890 : 0 : TAILQ_INIT(IGC_DEV_PRIVATE_FLOW_LIST(dev));
891 : 0 : }
892 : :
893 : : /* Destroy all flow in the list and free memory */
894 : : int
895 : 0 : igc_flow_flush(struct rte_eth_dev *dev,
896 : : __rte_unused struct rte_flow_error *error)
897 : : {
898 : 0 : struct igc_flow_list *list = IGC_DEV_PRIVATE_FLOW_LIST(dev);
899 : : struct rte_flow *flow;
900 : :
901 [ # # ]: 0 : while ((flow = TAILQ_FIRST(list)) != NULL) {
902 : 0 : igc_disable_flow(dev, flow);
903 : : igc_remove_flow(list, flow);
904 : : }
905 : :
906 : 0 : return 0;
907 : : }
908 : :
909 : : const struct rte_flow_ops igc_flow_ops = {
910 : : .validate = igc_flow_validate,
911 : : .create = igc_flow_create,
912 : : .destroy = igc_flow_destroy,
913 : : .flush = igc_flow_flush,
914 : : };
|