022d41775b5fe026b7f9e6dd6e200964dadbd244
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_flow.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4
5 #include "rte_eth_softnic_internals.h"
6 #include "rte_eth_softnic.h"
7
8 int
9 flow_attr_map_set(struct pmd_internals *softnic,
10                 uint32_t group_id,
11                 int ingress,
12                 const char *pipeline_name,
13                 uint32_t table_id)
14 {
15         struct pipeline *pipeline;
16         struct flow_attr_map *map;
17
18         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS ||
19                         pipeline_name == NULL)
20                 return -1;
21
22         pipeline = softnic_pipeline_find(softnic, pipeline_name);
23         if (pipeline == NULL ||
24                         table_id >= pipeline->n_tables)
25                 return -1;
26
27         map = (ingress) ? &softnic->flow.ingress_map[group_id] :
28                 &softnic->flow.egress_map[group_id];
29         strcpy(map->pipeline_name, pipeline_name);
30         map->table_id = table_id;
31         map->valid = 1;
32
33         return 0;
34 }
35
36 struct flow_attr_map *
37 flow_attr_map_get(struct pmd_internals *softnic,
38                 uint32_t group_id,
39                 int ingress)
40 {
41         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS)
42                 return NULL;
43
44         return (ingress) ? &softnic->flow.ingress_map[group_id] :
45                 &softnic->flow.egress_map[group_id];
46 }
47
48 static int
49 flow_pipeline_table_get(struct pmd_internals *softnic,
50                 const struct rte_flow_attr *attr,
51                 const char **pipeline_name,
52                 uint32_t *table_id,
53                 struct rte_flow_error *error)
54 {
55         struct flow_attr_map *map;
56
57         if (attr == NULL)
58                 return rte_flow_error_set(error,
59                                 EINVAL,
60                                 RTE_FLOW_ERROR_TYPE_ATTR,
61                                 NULL,
62                                 "Null attr");
63
64         if (!attr->ingress && !attr->egress)
65                 return rte_flow_error_set(error,
66                                 EINVAL,
67                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
68                                 attr,
69                                 "Ingress/egress not specified");
70
71         if (attr->ingress && attr->egress)
72                 return rte_flow_error_set(error,
73                                 EINVAL,
74                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
75                                 attr,
76                                 "Setting both ingress and egress is not allowed");
77
78         map = flow_attr_map_get(softnic,
79                         attr->group,
80                         attr->ingress);
81         if (map == NULL ||
82                         map->valid == 0)
83                 return rte_flow_error_set(error,
84                                 EINVAL,
85                                 RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
86                                 attr,
87                                 "Invalid group ID");
88
89         if (pipeline_name)
90                 *pipeline_name = map->pipeline_name;
91
92         if (table_id)
93                 *table_id = map->table_id;
94
95         return 0;
96 }
97
98 union flow_item {
99         uint8_t raw[TABLE_RULE_MATCH_SIZE_MAX];
100         struct rte_flow_item_eth eth;
101         struct rte_flow_item_vlan vlan;
102         struct rte_flow_item_ipv4 ipv4;
103         struct rte_flow_item_ipv6 ipv6;
104         struct rte_flow_item_icmp icmp;
105         struct rte_flow_item_udp udp;
106         struct rte_flow_item_tcp tcp;
107         struct rte_flow_item_sctp sctp;
108         struct rte_flow_item_vxlan vxlan;
109         struct rte_flow_item_e_tag e_tag;
110         struct rte_flow_item_nvgre nvgre;
111         struct rte_flow_item_mpls mpls;
112         struct rte_flow_item_gre gre;
113         struct rte_flow_item_gtp gtp;
114         struct rte_flow_item_esp esp;
115         struct rte_flow_item_geneve geneve;
116         struct rte_flow_item_vxlan_gpe vxlan_gpe;
117         struct rte_flow_item_arp_eth_ipv4 arp_eth_ipv4;
118         struct rte_flow_item_ipv6_ext ipv6_ext;
119         struct rte_flow_item_icmp6 icmp6;
120         struct rte_flow_item_icmp6_nd_ns icmp6_nd_ns;
121         struct rte_flow_item_icmp6_nd_na icmp6_nd_na;
122         struct rte_flow_item_icmp6_nd_opt icmp6_nd_opt;
123         struct rte_flow_item_icmp6_nd_opt_sla_eth icmp6_nd_opt_sla_eth;
124         struct rte_flow_item_icmp6_nd_opt_tla_eth icmp6_nd_opt_tla_eth;
125 };
126
127 static const union flow_item flow_item_raw_mask;
128
129 static int
130 flow_item_is_proto(enum rte_flow_item_type type,
131         const void **mask,
132         size_t *size)
133 {
134         switch (type) {
135         case RTE_FLOW_ITEM_TYPE_RAW:
136                 *mask = &flow_item_raw_mask;
137                 *size = sizeof(flow_item_raw_mask);
138                 return 1; /* TRUE */
139
140         case RTE_FLOW_ITEM_TYPE_ETH:
141                 *mask = &rte_flow_item_eth_mask;
142                 *size = sizeof(struct rte_flow_item_eth);
143                 return 1; /* TRUE */
144
145         case RTE_FLOW_ITEM_TYPE_VLAN:
146                 *mask = &rte_flow_item_vlan_mask;
147                 *size = sizeof(struct rte_flow_item_vlan);
148                 return 1;
149
150         case RTE_FLOW_ITEM_TYPE_IPV4:
151                 *mask = &rte_flow_item_ipv4_mask;
152                 *size = sizeof(struct rte_flow_item_ipv4);
153                 return 1;
154
155         case RTE_FLOW_ITEM_TYPE_IPV6:
156                 *mask = &rte_flow_item_ipv6_mask;
157                 *size = sizeof(struct rte_flow_item_ipv6);
158                 return 1;
159
160         case RTE_FLOW_ITEM_TYPE_ICMP:
161                 *mask = &rte_flow_item_icmp_mask;
162                 *size = sizeof(struct rte_flow_item_icmp);
163                 return 1;
164
165         case RTE_FLOW_ITEM_TYPE_UDP:
166                 *mask = &rte_flow_item_udp_mask;
167                 *size = sizeof(struct rte_flow_item_udp);
168                 return 1;
169
170         case RTE_FLOW_ITEM_TYPE_TCP:
171                 *mask = &rte_flow_item_tcp_mask;
172                 *size = sizeof(struct rte_flow_item_tcp);
173                 return 1;
174
175         case RTE_FLOW_ITEM_TYPE_SCTP:
176                 *mask = &rte_flow_item_sctp_mask;
177                 *size = sizeof(struct rte_flow_item_sctp);
178                 return 1;
179
180         case RTE_FLOW_ITEM_TYPE_VXLAN:
181                 *mask = &rte_flow_item_vxlan_mask;
182                 *size = sizeof(struct rte_flow_item_vxlan);
183                 return 1;
184
185         case RTE_FLOW_ITEM_TYPE_E_TAG:
186                 *mask = &rte_flow_item_e_tag_mask;
187                 *size = sizeof(struct rte_flow_item_e_tag);
188                 return 1;
189
190         case RTE_FLOW_ITEM_TYPE_NVGRE:
191                 *mask = &rte_flow_item_nvgre_mask;
192                 *size = sizeof(struct rte_flow_item_nvgre);
193                 return 1;
194
195         case RTE_FLOW_ITEM_TYPE_MPLS:
196                 *mask = &rte_flow_item_mpls_mask;
197                 *size = sizeof(struct rte_flow_item_mpls);
198                 return 1;
199
200         case RTE_FLOW_ITEM_TYPE_GRE:
201                 *mask = &rte_flow_item_gre_mask;
202                 *size = sizeof(struct rte_flow_item_gre);
203                 return 1;
204
205         case RTE_FLOW_ITEM_TYPE_GTP:
206         case RTE_FLOW_ITEM_TYPE_GTPC:
207         case RTE_FLOW_ITEM_TYPE_GTPU:
208                 *mask = &rte_flow_item_gtp_mask;
209                 *size = sizeof(struct rte_flow_item_gtp);
210                 return 1;
211
212         case RTE_FLOW_ITEM_TYPE_ESP:
213                 *mask = &rte_flow_item_esp_mask;
214                 *size = sizeof(struct rte_flow_item_esp);
215                 return 1;
216
217         case RTE_FLOW_ITEM_TYPE_GENEVE:
218                 *mask = &rte_flow_item_geneve_mask;
219                 *size = sizeof(struct rte_flow_item_geneve);
220                 return 1;
221
222         case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
223                 *mask = &rte_flow_item_vxlan_gpe_mask;
224                 *size = sizeof(struct rte_flow_item_vxlan_gpe);
225                 return 1;
226
227         case RTE_FLOW_ITEM_TYPE_ARP_ETH_IPV4:
228                 *mask = &rte_flow_item_arp_eth_ipv4_mask;
229                 *size = sizeof(struct rte_flow_item_arp_eth_ipv4);
230                 return 1;
231
232         case RTE_FLOW_ITEM_TYPE_IPV6_EXT:
233                 *mask = &rte_flow_item_ipv6_ext_mask;
234                 *size = sizeof(struct rte_flow_item_ipv6_ext);
235                 return 1;
236
237         case RTE_FLOW_ITEM_TYPE_ICMP6:
238                 *mask = &rte_flow_item_icmp6_mask;
239                 *size = sizeof(struct rte_flow_item_icmp6);
240                 return 1;
241
242         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NS:
243                 *mask = &rte_flow_item_icmp6_nd_ns_mask;
244                 *size = sizeof(struct rte_flow_item_icmp6_nd_ns);
245                 return 1;
246
247         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NA:
248                 *mask = &rte_flow_item_icmp6_nd_na_mask;
249                 *size = sizeof(struct rte_flow_item_icmp6_nd_na);
250                 return 1;
251
252         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT:
253                 *mask = &rte_flow_item_icmp6_nd_opt_mask;
254                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt);
255                 return 1;
256
257         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_SLA_ETH:
258                 *mask = &rte_flow_item_icmp6_nd_opt_sla_eth_mask;
259                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth);
260                 return 1;
261
262         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_TLA_ETH:
263                 *mask = &rte_flow_item_icmp6_nd_opt_tla_eth_mask;
264                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth);
265                 return 1;
266
267         default: return 0; /* FALSE */
268         }
269 }
270
271 static int
272 flow_item_proto_preprocess(const struct rte_flow_item *item,
273         union flow_item *item_spec,
274         union flow_item *item_mask,
275         size_t *item_size,
276         int *item_disabled,
277         struct rte_flow_error *error)
278 {
279         const void *mask_default;
280         uint8_t *spec = (uint8_t *)item_spec;
281         uint8_t *mask = (uint8_t *)item_mask;
282         size_t size, i;
283
284         if (!flow_item_is_proto(item->type, &mask_default, &size))
285                 return rte_flow_error_set(error,
286                         ENOTSUP,
287                         RTE_FLOW_ERROR_TYPE_ITEM,
288                         item,
289                         "Item type not supported");
290
291         /* spec */
292         if (!item->spec) {
293                 /* If spec is NULL, then last and mask also have to be NULL. */
294                 if (item->last || item->mask)
295                         return rte_flow_error_set(error,
296                                 EINVAL,
297                                 RTE_FLOW_ERROR_TYPE_ITEM,
298                                 item,
299                                 "Invalid item (NULL spec with non-NULL last or mask)");
300
301                 memset(item_spec, 0, size);
302                 memset(item_mask, 0, size);
303                 *item_size = size;
304                 *item_disabled = 1; /* TRUE */
305                 return 0;
306         }
307
308         memcpy(spec, item->spec, size);
309         *item_size = size;
310
311         /* mask */
312         if (item->mask)
313                 memcpy(mask, item->mask, size);
314         else
315                 memcpy(mask, mask_default, size);
316
317         /* disabled */
318         for (i = 0; i < size; i++)
319                 if (mask[i])
320                         break;
321         *item_disabled = (i == size) ? 1 : 0;
322
323         /* Apply mask over spec. */
324         for (i = 0; i < size; i++)
325                 spec[i] &= mask[i];
326
327         /* last */
328         if (item->last) {
329                 uint8_t last[size];
330
331                 /* init last */
332                 memcpy(last, item->last, size);
333                 for (i = 0; i < size; i++)
334                         last[i] &= mask[i];
335
336                 /* check for range */
337                 for (i = 0; i < size; i++)
338                         if (last[i] != spec[i])
339                                 return rte_flow_error_set(error,
340                                         ENOTSUP,
341                                         RTE_FLOW_ERROR_TYPE_ITEM,
342                                         item,
343                                         "Range not supported");
344         }
345
346         return 0;
347 }
348
349 /***
350  * Skip disabled protocol items and VOID items
351  * until any of the mutually exclusive conditions
352  * from the list below takes place:
353  *    (A) A protocol present in the proto_mask
354  *        is met (either ENABLED or DISABLED);
355  *    (B) A protocol NOT present in the proto_mask is met in ENABLED state;
356  *    (C) The END item is met.
357  */
358 static int
359 flow_item_skip_disabled_protos(const struct rte_flow_item **item,
360         uint64_t proto_mask,
361         size_t *length,
362         struct rte_flow_error *error)
363 {
364         size_t len = 0;
365
366         for ( ; (*item)->type != RTE_FLOW_ITEM_TYPE_END; (*item)++) {
367                 union flow_item spec, mask;
368                 size_t size;
369                 int disabled = 0, status;
370
371                 if ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
372                         continue;
373
374                 status = flow_item_proto_preprocess(*item,
375                                 &spec,
376                                 &mask,
377                                 &size,
378                                 &disabled,
379                                 error);
380                 if (status)
381                         return status;
382
383                 if ((proto_mask & (1LLU << (*item)->type)) ||
384                                 !disabled)
385                         break;
386
387                 len += size;
388         }
389
390         if (length)
391                 *length = len;
392
393         return 0;
394 }
395
396 #define FLOW_ITEM_PROTO_IP \
397         ((1LLU << RTE_FLOW_ITEM_TYPE_IPV4) | \
398          (1LLU << RTE_FLOW_ITEM_TYPE_IPV6))
399
400 static int
401 flow_rule_match_acl_get(struct pmd_internals *softnic __rte_unused,
402                 struct pipeline *pipeline __rte_unused,
403                 struct softnic_table *table __rte_unused,
404                 const struct rte_flow_attr *attr,
405                 const struct rte_flow_item *item,
406                 struct softnic_table_rule_match *rule_match,
407                 struct rte_flow_error *error)
408 {
409         union flow_item spec, mask;
410         size_t size, length = 0;
411         int disabled = 0, status;
412
413         memset(rule_match, 0, sizeof(*rule_match));
414         rule_match->match_type = TABLE_ACL;
415         rule_match->match.acl.priority = attr->priority;
416
417         /* VOID or disabled protos only, if any. */
418         status = flow_item_skip_disabled_protos(&item,
419                         FLOW_ITEM_PROTO_IP, &length, error);
420         if (status)
421                 return status;
422
423         /* IP only. */
424         status = flow_item_proto_preprocess(item, &spec, &mask,
425                         &size, &disabled, error);
426         if (status)
427                 return status;
428
429         switch (item->type) {
430         default:
431                 return rte_flow_error_set(error,
432                         ENOTSUP,
433                         RTE_FLOW_ERROR_TYPE_ITEM,
434                         item,
435                         "ACL: IP protocol required");
436         } /* switch */
437 }
438
439 static int
440 flow_rule_match_get(struct pmd_internals *softnic,
441                 struct pipeline *pipeline,
442                 struct softnic_table *table,
443                 const struct rte_flow_attr *attr,
444                 const struct rte_flow_item *item,
445                 struct softnic_table_rule_match *rule_match,
446                 struct rte_flow_error *error)
447 {
448         switch (table->params.match_type) {
449         case TABLE_ACL:
450                 return flow_rule_match_acl_get(softnic,
451                         pipeline,
452                         table,
453                         attr,
454                         item,
455                         rule_match,
456                         error);
457                 /* FALLTHROUGH */
458         default:
459                 return rte_flow_error_set(error,
460                         ENOTSUP,
461                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
462                         NULL,
463                         "Unsupported pipeline table match type");
464         }
465 }
466
467 static int
468 pmd_flow_validate(struct rte_eth_dev *dev,
469                 const struct rte_flow_attr *attr,
470                 const struct rte_flow_item item[],
471                 const struct rte_flow_action action[],
472                 struct rte_flow_error *error)
473 {
474         struct softnic_table_rule_match rule_match;
475
476         struct pmd_internals *softnic = dev->data->dev_private;
477         struct pipeline *pipeline;
478         struct softnic_table *table;
479         const char *pipeline_name = NULL;
480         uint32_t table_id = 0;
481         int status;
482
483         /* Check input parameters. */
484         if (attr == NULL)
485                 return rte_flow_error_set(error,
486                                 EINVAL,
487                                 RTE_FLOW_ERROR_TYPE_ATTR,
488                                 NULL, "Null attr");
489
490         if (item == NULL)
491                 return rte_flow_error_set(error,
492                                 EINVAL,
493                                 RTE_FLOW_ERROR_TYPE_ITEM,
494                                 NULL,
495                                 "Null item");
496
497         if (action == NULL)
498                 return rte_flow_error_set(error,
499                                 EINVAL,
500                                 RTE_FLOW_ERROR_TYPE_ACTION,
501                                 NULL,
502                                 "Null action");
503
504         /* Identify the pipeline table to add this flow to. */
505         status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
506                                         &table_id, error);
507         if (status)
508                 return status;
509
510         pipeline = softnic_pipeline_find(softnic, pipeline_name);
511         if (pipeline == NULL)
512                 return rte_flow_error_set(error,
513                                 EINVAL,
514                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
515                                 NULL,
516                                 "Invalid pipeline name");
517
518         if (table_id >= pipeline->n_tables)
519                 return rte_flow_error_set(error,
520                                 EINVAL,
521                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
522                                 NULL,
523                                 "Invalid pipeline table ID");
524
525         table = &pipeline->table[table_id];
526
527         /* Rule match. */
528         memset(&rule_match, 0, sizeof(rule_match));
529         status = flow_rule_match_get(softnic,
530                         pipeline,
531                         table,
532                         attr,
533                         item,
534                         &rule_match,
535                         error);
536         if (status)
537                 return status;
538
539         return 0;
540 }
541
542 const struct rte_flow_ops pmd_flow_ops = {
543         .validate = pmd_flow_validate,
544 };