lib: use SPDX tag for Intel copyright files
[dpdk.git] / lib / librte_flow_classify / rte_flow_classify.c
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 #include <rte_table_acl.h>
9 #include <stdbool.h>
10
11 int librte_flow_classify_logtype;
12
13 static struct rte_eth_ntuple_filter ntuple_filter;
14 static uint32_t unique_id = 1;
15
16
17 struct rte_flow_classify_table_entry {
18         /* meta-data for classify rule */
19         uint32_t rule_id;
20 };
21
22 struct rte_table {
23         /* Input parameters */
24         struct rte_table_ops ops;
25         uint32_t entry_size;
26         enum rte_flow_classify_table_type type;
27
28         /* Handle to the low-level table object */
29         void *h_table;
30 };
31
32 #define RTE_FLOW_CLASSIFIER_MAX_NAME_SZ 256
33
34 struct rte_flow_classifier {
35         /* Input parameters */
36         char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
37         int socket_id;
38         enum rte_flow_classify_table_type type;
39
40         /* Internal tables */
41         struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
42         uint32_t num_tables;
43         uint16_t nb_pkts;
44         struct rte_flow_classify_table_entry
45                 *entries[RTE_PORT_IN_BURST_SIZE_MAX];
46 } __rte_cache_aligned;
47
48 enum {
49         PROTO_FIELD_IPV4,
50         SRC_FIELD_IPV4,
51         DST_FIELD_IPV4,
52         SRCP_FIELD_IPV4,
53         DSTP_FIELD_IPV4,
54         NUM_FIELDS_IPV4
55 };
56
57 struct acl_keys {
58         struct rte_table_acl_rule_add_params key_add; /* add key */
59         struct rte_table_acl_rule_delete_params key_del; /* delete key */
60 };
61
62 struct classify_rules {
63         enum rte_flow_classify_rule_type type;
64         union {
65                 struct rte_flow_classify_ipv4_5tuple ipv4_5tuple;
66         } u;
67 };
68
69 struct rte_flow_classify_rule {
70         uint32_t id; /* unique ID of classify rule */
71         struct rte_flow_action action; /* action when match found */
72         struct classify_rules rules; /* union of rules */
73         union {
74                 struct acl_keys key;
75         } u;
76         int key_found;   /* rule key found in table */
77         void *entry;     /* pointer to buffer to hold rule meta data */
78         void *entry_ptr; /* handle to the table entry for rule meta data */
79 };
80
81 static int
82 flow_classify_parse_flow(
83                    const struct rte_flow_attr *attr,
84                    const struct rte_flow_item pattern[],
85                    const struct rte_flow_action actions[],
86                    struct rte_flow_error *error)
87 {
88         struct rte_flow_item *items;
89         parse_filter_t parse_filter;
90         uint32_t item_num = 0;
91         uint32_t i = 0;
92         int ret;
93
94         memset(&ntuple_filter, 0, sizeof(ntuple_filter));
95
96         /* Get the non-void item number of pattern */
97         while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
98                 if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)
99                         item_num++;
100                 i++;
101         }
102         item_num++;
103
104         items = malloc(item_num * sizeof(struct rte_flow_item));
105         if (!items) {
106                 rte_flow_error_set(error, ENOMEM,
107                                 RTE_FLOW_ERROR_TYPE_ITEM_NUM,
108                                 NULL, "No memory for pattern items.");
109                 return -ENOMEM;
110         }
111
112         memset(items, 0, item_num * sizeof(struct rte_flow_item));
113         classify_pattern_skip_void_item(items, pattern);
114
115         parse_filter = classify_find_parse_filter_func(items);
116         if (!parse_filter) {
117                 rte_flow_error_set(error, EINVAL,
118                                 RTE_FLOW_ERROR_TYPE_ITEM,
119                                 pattern, "Unsupported pattern");
120                 free(items);
121                 return -EINVAL;
122         }
123
124         ret = parse_filter(attr, items, actions, &ntuple_filter, error);
125         free(items);
126         return ret;
127 }
128
129
130 #define uint32_t_to_char(ip, a, b, c, d) do {\
131                 *a = (unsigned char)(ip >> 24 & 0xff);\
132                 *b = (unsigned char)(ip >> 16 & 0xff);\
133                 *c = (unsigned char)(ip >> 8 & 0xff);\
134                 *d = (unsigned char)(ip & 0xff);\
135         } while (0)
136
137 static inline void
138 print_acl_ipv4_key_add(struct rte_table_acl_rule_add_params *key)
139 {
140         unsigned char a, b, c, d;
141
142         printf("%s:    0x%02hhx/0x%hhx ", __func__,
143                 key->field_value[PROTO_FIELD_IPV4].value.u8,
144                 key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
145
146         uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
147                         &a, &b, &c, &d);
148         printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
149                         key->field_value[SRC_FIELD_IPV4].mask_range.u32);
150
151         uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
152                         &a, &b, &c, &d);
153         printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
154                         key->field_value[DST_FIELD_IPV4].mask_range.u32);
155
156         printf("%hu : 0x%x %hu : 0x%x",
157                 key->field_value[SRCP_FIELD_IPV4].value.u16,
158                 key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
159                 key->field_value[DSTP_FIELD_IPV4].value.u16,
160                 key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
161
162         printf(" priority: 0x%x\n", key->priority);
163 }
164
165 static inline void
166 print_acl_ipv4_key_delete(struct rte_table_acl_rule_delete_params *key)
167 {
168         unsigned char a, b, c, d;
169
170         printf("%s: 0x%02hhx/0x%hhx ", __func__,
171                 key->field_value[PROTO_FIELD_IPV4].value.u8,
172                 key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
173
174         uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
175                         &a, &b, &c, &d);
176         printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
177                         key->field_value[SRC_FIELD_IPV4].mask_range.u32);
178
179         uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
180                         &a, &b, &c, &d);
181         printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
182                         key->field_value[DST_FIELD_IPV4].mask_range.u32);
183
184         printf("%hu : 0x%x %hu : 0x%x\n",
185                 key->field_value[SRCP_FIELD_IPV4].value.u16,
186                 key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
187                 key->field_value[DSTP_FIELD_IPV4].value.u16,
188                 key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
189 }
190
191 static int
192 rte_flow_classifier_check_params(struct rte_flow_classifier_params *params)
193 {
194         if (params == NULL) {
195                 RTE_FLOW_CLASSIFY_LOG(ERR,
196                         "%s: Incorrect value for parameter params\n", __func__);
197                 return -EINVAL;
198         }
199
200         /* name */
201         if (params->name == NULL) {
202                 RTE_FLOW_CLASSIFY_LOG(ERR,
203                         "%s: Incorrect value for parameter name\n", __func__);
204                 return -EINVAL;
205         }
206
207         /* socket */
208         if ((params->socket_id < 0) ||
209             (params->socket_id >= RTE_MAX_NUMA_NODES)) {
210                 RTE_FLOW_CLASSIFY_LOG(ERR,
211                         "%s: Incorrect value for parameter socket_id\n",
212                         __func__);
213                 return -EINVAL;
214         }
215
216         return 0;
217 }
218
219 struct rte_flow_classifier *
220 rte_flow_classifier_create(struct rte_flow_classifier_params *params)
221 {
222         struct rte_flow_classifier *cls;
223         int ret;
224
225         /* Check input parameters */
226         ret = rte_flow_classifier_check_params(params);
227         if (ret != 0) {
228                 RTE_FLOW_CLASSIFY_LOG(ERR,
229                         "%s: flow classifier params check failed (%d)\n",
230                         __func__, ret);
231                 return NULL;
232         }
233
234         /* Allocate memory for the flow classifier */
235         cls = rte_zmalloc_socket("FLOW_CLASSIFIER",
236                         sizeof(struct rte_flow_classifier),
237                         RTE_CACHE_LINE_SIZE, params->socket_id);
238
239         if (cls == NULL) {
240                 RTE_FLOW_CLASSIFY_LOG(ERR,
241                         "%s: flow classifier memory allocation failed\n",
242                         __func__);
243                 return NULL;
244         }
245
246         /* Save input parameters */
247         snprintf(cls->name, RTE_FLOW_CLASSIFIER_MAX_NAME_SZ, "%s",
248                         params->name);
249         cls->socket_id = params->socket_id;
250         cls->type = params->type;
251
252         /* Initialize flow classifier internal data structure */
253         cls->num_tables = 0;
254
255         return cls;
256 }
257
258 static void
259 rte_flow_classify_table_free(struct rte_table *table)
260 {
261         if (table->ops.f_free != NULL)
262                 table->ops.f_free(table->h_table);
263 }
264
265 int
266 rte_flow_classifier_free(struct rte_flow_classifier *cls)
267 {
268         uint32_t i;
269
270         /* Check input parameters */
271         if (cls == NULL) {
272                 RTE_FLOW_CLASSIFY_LOG(ERR,
273                         "%s: rte_flow_classifier parameter is NULL\n",
274                         __func__);
275                 return -EINVAL;
276         }
277
278         /* Free tables */
279         for (i = 0; i < cls->num_tables; i++) {
280                 struct rte_table *table = &cls->tables[i];
281
282                 rte_flow_classify_table_free(table);
283         }
284
285         /* Free flow classifier memory */
286         rte_free(cls);
287
288         return 0;
289 }
290
291 static int
292 rte_table_check_params(struct rte_flow_classifier *cls,
293                 struct rte_flow_classify_table_params *params,
294                 uint32_t *table_id)
295 {
296         if (cls == NULL) {
297                 RTE_FLOW_CLASSIFY_LOG(ERR,
298                         "%s: flow classifier parameter is NULL\n",
299                         __func__);
300                 return -EINVAL;
301         }
302         if (params == NULL) {
303                 RTE_FLOW_CLASSIFY_LOG(ERR, "%s: params parameter is NULL\n",
304                         __func__);
305                 return -EINVAL;
306         }
307         if (table_id == NULL) {
308                 RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is NULL\n",
309                         __func__);
310                 return -EINVAL;
311         }
312
313         /* ops */
314         if (params->ops == NULL) {
315                 RTE_FLOW_CLASSIFY_LOG(ERR, "%s: params->ops is NULL\n",
316                         __func__);
317                 return -EINVAL;
318         }
319
320         if (params->ops->f_create == NULL) {
321                 RTE_FLOW_CLASSIFY_LOG(ERR,
322                         "%s: f_create function pointer is NULL\n", __func__);
323                 return -EINVAL;
324         }
325
326         if (params->ops->f_lookup == NULL) {
327                 RTE_FLOW_CLASSIFY_LOG(ERR,
328                         "%s: f_lookup function pointer is NULL\n", __func__);
329                 return -EINVAL;
330         }
331
332         /* De we have room for one more table? */
333         if (cls->num_tables == RTE_FLOW_CLASSIFY_TABLE_MAX) {
334                 RTE_FLOW_CLASSIFY_LOG(ERR,
335                         "%s: Incorrect value for num_tables parameter\n",
336                         __func__);
337                 return -EINVAL;
338         }
339
340         return 0;
341 }
342
343 int
344 rte_flow_classify_table_create(struct rte_flow_classifier *cls,
345         struct rte_flow_classify_table_params *params,
346         uint32_t *table_id)
347 {
348         struct rte_table *table;
349         void *h_table;
350         uint32_t entry_size, id;
351         int ret;
352
353         /* Check input arguments */
354         ret = rte_table_check_params(cls, params, table_id);
355         if (ret != 0)
356                 return ret;
357
358         id = cls->num_tables;
359         table = &cls->tables[id];
360
361         /* calculate table entry size */
362         entry_size = sizeof(struct rte_flow_classify_table_entry);
363
364         /* Create the table */
365         h_table = params->ops->f_create(params->arg_create, cls->socket_id,
366                 entry_size);
367         if (h_table == NULL) {
368                 RTE_FLOW_CLASSIFY_LOG(ERR, "%s: Table creation failed\n",
369                         __func__);
370                 return -EINVAL;
371         }
372
373         /* Commit current table to the classifier */
374         cls->num_tables++;
375         *table_id = id;
376
377         /* Save input parameters */
378         memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
379
380         /* Initialize table internal data structure */
381         table->entry_size = entry_size;
382         table->h_table = h_table;
383
384         return 0;
385 }
386
387 static struct rte_flow_classify_rule *
388 allocate_acl_ipv4_5tuple_rule(void)
389 {
390         struct rte_flow_classify_rule *rule;
391         int log_level;
392
393         rule = malloc(sizeof(struct rte_flow_classify_rule));
394         if (!rule)
395                 return rule;
396
397         memset(rule, 0, sizeof(struct rte_flow_classify_rule));
398         rule->id = unique_id++;
399         rule->rules.type = RTE_FLOW_CLASSIFY_RULE_TYPE_IPV4_5TUPLE;
400
401         memcpy(&rule->action, classify_get_flow_action(),
402                sizeof(struct rte_flow_action));
403
404         /* key add values */
405         rule->u.key.key_add.priority = ntuple_filter.priority;
406         rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
407                         ntuple_filter.proto_mask;
408         rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
409                         ntuple_filter.proto;
410         rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
411         rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
412
413         rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
414                         ntuple_filter.src_ip_mask;
415         rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
416                         ntuple_filter.src_ip;
417         rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
418         rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
419
420         rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
421                         ntuple_filter.dst_ip_mask;
422         rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
423                         ntuple_filter.dst_ip;
424         rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
425         rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
426
427         rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
428                         ntuple_filter.src_port_mask;
429         rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
430                         ntuple_filter.src_port;
431         rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
432         rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
433
434         rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
435                         ntuple_filter.dst_port_mask;
436         rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
437                         ntuple_filter.dst_port;
438         rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
439         rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
440
441         log_level = rte_log_get_level(librte_flow_classify_logtype);
442
443         if (log_level == RTE_LOG_DEBUG)
444                 print_acl_ipv4_key_add(&rule->u.key.key_add);
445
446         /* key delete values */
447         memcpy(&rule->u.key.key_del.field_value[PROTO_FIELD_IPV4],
448                &rule->u.key.key_add.field_value[PROTO_FIELD_IPV4],
449                NUM_FIELDS_IPV4 * sizeof(struct rte_acl_field));
450
451         if (log_level == RTE_LOG_DEBUG)
452                 print_acl_ipv4_key_delete(&rule->u.key.key_del);
453
454         return rule;
455 }
456
457 struct rte_flow_classify_rule *
458 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
459                 uint32_t table_id,
460                 int *key_found,
461                 const struct rte_flow_attr *attr,
462                 const struct rte_flow_item pattern[],
463                 const struct rte_flow_action actions[],
464                 struct rte_flow_error *error)
465 {
466         struct rte_flow_classify_rule *rule;
467         struct rte_flow_classify_table_entry *table_entry;
468         int ret;
469
470         if (!error)
471                 return NULL;
472
473         if (!cls) {
474                 rte_flow_error_set(error, EINVAL,
475                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
476                                 NULL, "NULL classifier.");
477                 return NULL;
478         }
479
480         if (table_id >= cls->num_tables) {
481                 rte_flow_error_set(error, EINVAL,
482                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
483                                 NULL, "invalid table_id.");
484                 return NULL;
485         }
486
487         if (key_found == NULL) {
488                 rte_flow_error_set(error, EINVAL,
489                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
490                                 NULL, "NULL key_found.");
491                 return NULL;
492         }
493
494         if (!pattern) {
495                 rte_flow_error_set(error, EINVAL,
496                                 RTE_FLOW_ERROR_TYPE_ITEM_NUM,
497                                 NULL, "NULL pattern.");
498                 return NULL;
499         }
500
501         if (!actions) {
502                 rte_flow_error_set(error, EINVAL,
503                                 RTE_FLOW_ERROR_TYPE_ACTION_NUM,
504                                 NULL, "NULL action.");
505                 return NULL;
506         }
507
508         if (!attr) {
509                 rte_flow_error_set(error, EINVAL,
510                                 RTE_FLOW_ERROR_TYPE_ATTR,
511                                 NULL, "NULL attribute.");
512                 return NULL;
513         }
514
515         /* parse attr, pattern and actions */
516         ret = flow_classify_parse_flow(attr, pattern, actions, error);
517         if (ret < 0)
518                 return NULL;
519
520         switch (cls->type) {
521         case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
522                 rule = allocate_acl_ipv4_5tuple_rule();
523                 if (!rule)
524                         return NULL;
525                 break;
526         default:
527                 return NULL;
528         }
529
530         rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
531         if (!rule->entry) {
532                 free(rule);
533                 return NULL;
534         }
535
536         table_entry = rule->entry;
537         table_entry->rule_id = rule->id;
538
539         if (cls->tables[table_id].ops.f_add != NULL) {
540                 ret = cls->tables[table_id].ops.f_add(
541                         cls->tables[table_id].h_table,
542                         &rule->u.key.key_add,
543                         rule->entry,
544                         &rule->key_found,
545                         &rule->entry_ptr);
546                 if (ret) {
547                         free(rule->entry);
548                         free(rule);
549                         return NULL;
550                 }
551                 *key_found = rule->key_found;
552         }
553         return rule;
554 }
555
556 int
557 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
558                 uint32_t table_id,
559                 struct rte_flow_classify_rule *rule)
560 {
561         int ret = -EINVAL;
562
563         if (!cls || !rule || table_id >= cls->num_tables)
564                 return ret;
565
566         if (cls->tables[table_id].ops.f_delete != NULL)
567                 ret = cls->tables[table_id].ops.f_delete(
568                         cls->tables[table_id].h_table,
569                         &rule->u.key.key_del,
570                         &rule->key_found,
571                         &rule->entry);
572
573         return ret;
574 }
575
576 static int
577 flow_classifier_lookup(struct rte_flow_classifier *cls,
578                 uint32_t table_id,
579                 struct rte_mbuf **pkts,
580                 const uint16_t nb_pkts)
581 {
582         int ret = -EINVAL;
583         uint64_t pkts_mask;
584         uint64_t lookup_hit_mask;
585
586         pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
587         ret = cls->tables[table_id].ops.f_lookup(
588                 cls->tables[table_id].h_table,
589                 pkts, pkts_mask, &lookup_hit_mask,
590                 (void **)cls->entries);
591
592         if (!ret && lookup_hit_mask)
593                 cls->nb_pkts = nb_pkts;
594         else
595                 cls->nb_pkts = 0;
596
597         return ret;
598 }
599
600 static int
601 action_apply(struct rte_flow_classifier *cls,
602                 struct rte_flow_classify_rule *rule,
603                 struct rte_flow_classify_stats *stats)
604 {
605         struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
606         uint64_t count = 0;
607         int i;
608         int ret = -EINVAL;
609
610         switch (rule->action.type) {
611         case RTE_FLOW_ACTION_TYPE_COUNT:
612                 for (i = 0; i < cls->nb_pkts; i++) {
613                         if (rule->id == cls->entries[i]->rule_id)
614                                 count++;
615                 }
616                 if (count) {
617                         ret = 0;
618                         ntuple_stats =
619                                 (struct rte_flow_classify_ipv4_5tuple_stats *)
620                                 stats->stats;
621                         ntuple_stats->counter1 = count;
622                         ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
623                 }
624                 break;
625         default:
626                 ret = -ENOTSUP;
627                 break;
628         }
629
630         return ret;
631 }
632
633 int
634 rte_flow_classifier_query(struct rte_flow_classifier *cls,
635                 uint32_t table_id,
636                 struct rte_mbuf **pkts,
637                 const uint16_t nb_pkts,
638                 struct rte_flow_classify_rule *rule,
639                 struct rte_flow_classify_stats *stats)
640 {
641         int ret = -EINVAL;
642
643         if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
644                 table_id >= cls->num_tables)
645                 return ret;
646
647         ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
648         if (!ret)
649                 ret = action_apply(cls, rule, stats);
650         return ret;
651 }
652
653 RTE_INIT(librte_flow_classify_init_log);
654
655 static void
656 librte_flow_classify_init_log(void)
657 {
658         librte_flow_classify_logtype =
659                 rte_log_register("librte.flow_classify");
660         if (librte_flow_classify_logtype >= 0)
661                 rte_log_set_level(librte_flow_classify_logtype, RTE_LOG_INFO);
662 }