11dfee226bd0cdbd8d68ef5915d2137b1c656e98
[dpdk.git] / test / test / test_flow_classify.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <errno.h>
7
8 #include "test.h"
9
10 #include <rte_string_fns.h>
11 #include <rte_mbuf.h>
12 #include <rte_byteorder.h>
13 #include <rte_ip.h>
14 #include <rte_acl.h>
15 #include <rte_common.h>
16 #include <rte_table_acl.h>
17 #include <rte_flow.h>
18 #include <rte_flow_classify.h>
19
20 #include "packet_burst_generator.h"
21 #include "test_flow_classify.h"
22
23
24 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
25 struct flow_classifier *cls;
26
27 struct flow_classifier {
28         struct rte_flow_classifier *cls;
29         uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
30         uint32_t n_tables;
31 };
32
33 struct flow_classifier_acl {
34         struct flow_classifier cls;
35 } __rte_cache_aligned;
36
37 /*
38  * test functions by passing invalid or
39  * non-workable parameters.
40  */
41 static int
42 test_invalid_parameters(void)
43 {
44         struct rte_flow_classify_rule *rule;
45         int ret;
46
47         rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
48                         NULL, NULL);
49         if (rule) {
50                 printf("Line %i: flow_classifier_table_entry_add", __LINE__);
51                 printf(" with NULL param should have failed!\n");
52                 return -1;
53         }
54
55         ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
56         if (!ret) {
57                 printf("Line %i: rte_flow_classify_table_entry_delete",
58                         __LINE__);
59                 printf(" with NULL param should have failed!\n");
60                 return -1;
61         }
62
63         ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
64         if (!ret) {
65                 printf("Line %i: flow_classifier_query", __LINE__);
66                 printf(" with NULL param should have failed!\n");
67                 return -1;
68         }
69
70         rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
71                 NULL, &error);
72         if (rule) {
73                 printf("Line %i: flow_classify_table_entry_add ", __LINE__);
74                 printf("with NULL param should have failed!\n");
75                 return -1;
76         }
77
78         ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
79         if (!ret) {
80                 printf("Line %i: rte_flow_classify_table_entry_delete",
81                         __LINE__);
82                 printf("with NULL param should have failed!\n");
83                 return -1;
84         }
85
86         ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
87         if (!ret) {
88                 printf("Line %i: flow_classifier_query", __LINE__);
89                 printf(" with NULL param should have failed!\n");
90                 return -1;
91         }
92         return 0;
93 }
94
95 static int
96 test_valid_parameters(void)
97 {
98         struct rte_flow_classify_rule *rule;
99         int ret;
100         int key_found;
101
102         /*
103          * set up parameters for rte_flow_classify_table_entry_add and
104          * rte_flow_classify_table_entry_delete
105          */
106
107         attr.ingress = 1;
108         attr.priority = 1;
109         pattern[0] = eth_item;
110         pattern[1] = ipv4_udp_item_1;
111         pattern[2] = udp_item_1;
112         pattern[3] = end_item;
113         actions[0] = count_action;
114         actions[1] = end_action;
115
116         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
117                         &attr, pattern, actions, &error);
118         if (!rule) {
119                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
120                 printf(" should not have failed!\n");
121                 return -1;
122         }
123
124         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
125         if (ret) {
126                 printf("Line %i: rte_flow_classify_table_entry_delete",
127                         __LINE__);
128                 printf(" should not have failed!\n");
129                 return -1;
130         }
131         return 0;
132 }
133
134 static int
135 test_invalid_patterns(void)
136 {
137         struct rte_flow_classify_rule *rule;
138         int ret;
139         int key_found;
140
141         /*
142          * set up parameters for rte_flow_classify_table_entry_add and
143          * rte_flow_classify_table_entry_delete
144          */
145
146         attr.ingress = 1;
147         attr.priority = 1;
148         pattern[0] = eth_item_bad;
149         pattern[1] = ipv4_udp_item_1;
150         pattern[2] = udp_item_1;
151         pattern[3] = end_item;
152         actions[0] = count_action;
153         actions[1] = end_action;
154
155         pattern[0] = eth_item;
156         pattern[1] = ipv4_udp_item_bad;
157         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
158                         &attr, pattern, actions, &error);
159         if (rule) {
160                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
161                 printf(" should have failed!\n");
162                 return -1;
163         }
164
165         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
166         if (!ret) {
167                 printf("Line %i: rte_flow_classify_table_entry_delete",
168                         __LINE__);
169                 printf(" should have failed!\n");
170                 return -1;
171         }
172
173         pattern[1] = ipv4_udp_item_1;
174         pattern[2] = udp_item_bad;
175         pattern[3] = end_item_bad;
176         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
177                         &attr, pattern, actions, &error);
178         if (rule) {
179                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
180                 printf(" should have failed!\n");
181                 return -1;
182         }
183
184         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
185         if (!ret) {
186                 printf("Line %i: rte_flow_classify_table_entry_delete",
187                         __LINE__);
188                 printf(" should have failed!\n");
189                 return -1;
190         }
191         return 0;
192 }
193
194 static int
195 test_invalid_actions(void)
196 {
197         struct rte_flow_classify_rule *rule;
198         int ret;
199         int key_found;
200
201         /*
202          * set up parameters for rte_flow_classify_table_entry_add and
203          * rte_flow_classify_table_entry_delete
204          */
205
206         attr.ingress = 1;
207         attr.priority = 1;
208         pattern[0] = eth_item;
209         pattern[1] = ipv4_udp_item_1;
210         pattern[2] = udp_item_1;
211         pattern[3] = end_item;
212         actions[0] = count_action_bad;
213         actions[1] = end_action;
214
215         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
216                         &attr, pattern, actions, &error);
217         if (rule) {
218                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
219                 printf(" should have failed!\n");
220                 return -1;
221         }
222
223         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
224         if (!ret) {
225                 printf("Line %i: rte_flow_classify_table_entry_delete",
226                         __LINE__);
227                 printf(" should have failed!\n");
228                 return -1;
229         }
230
231         actions[0] = count_action;
232         actions[1] = end_action_bad;
233
234         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
235                         &attr, pattern, actions, &error);
236         if (rule) {
237                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
238                 printf(" should have failed!\n");
239                 return -1;
240         }
241
242         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
243         if (!ret) {
244                 printf("Line %i: rte_flow_classify_table_entry_delete",
245                         __LINE__);
246                 printf("should have failed!\n");
247                 return -1;
248         }
249         return 0;
250 }
251
252 static int
253 init_ipv4_udp_traffic(struct rte_mempool *mp,
254              struct rte_mbuf **pkts_burst, uint32_t burst_size)
255 {
256         struct ether_hdr pkt_eth_hdr;
257         struct ipv4_hdr pkt_ipv4_hdr;
258         struct udp_hdr pkt_udp_hdr;
259         uint32_t src_addr = IPV4_ADDR(2, 2, 2, 3);
260         uint32_t dst_addr = IPV4_ADDR(2, 2, 2, 7);
261         uint16_t src_port = 32;
262         uint16_t dst_port = 33;
263         uint16_t pktlen;
264
265         static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
266         static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
267
268         printf("Set up IPv4 UDP traffic\n");
269         initialize_eth_header(&pkt_eth_hdr,
270                 (struct ether_addr *)src_mac,
271                 (struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
272         pktlen = (uint16_t)(sizeof(struct ether_hdr));
273         printf("ETH  pktlen %u\n", pktlen);
274
275         pktlen = initialize_ipv4_header(&pkt_ipv4_hdr, src_addr, dst_addr,
276                                         pktlen);
277         printf("ETH + IPv4 pktlen %u\n", pktlen);
278
279         pktlen = initialize_udp_header(&pkt_udp_hdr, src_port, dst_port,
280                                         pktlen);
281         printf("ETH + IPv4 + UDP pktlen %u\n\n", pktlen);
282
283         return generate_packet_burst(mp, pkts_burst, &pkt_eth_hdr,
284                                      0, &pkt_ipv4_hdr, 1,
285                                      &pkt_udp_hdr, burst_size,
286                                      PACKET_BURST_GEN_PKT_LEN, 1);
287 }
288
289 static int
290 init_ipv4_tcp_traffic(struct rte_mempool *mp,
291              struct rte_mbuf **pkts_burst, uint32_t burst_size)
292 {
293         struct ether_hdr pkt_eth_hdr;
294         struct ipv4_hdr pkt_ipv4_hdr;
295         struct tcp_hdr pkt_tcp_hdr;
296         uint32_t src_addr = IPV4_ADDR(1, 2, 3, 4);
297         uint32_t dst_addr = IPV4_ADDR(5, 6, 7, 8);
298         uint16_t src_port = 16;
299         uint16_t dst_port = 17;
300         uint16_t pktlen;
301
302         static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
303         static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
304
305         printf("Set up IPv4 TCP traffic\n");
306         initialize_eth_header(&pkt_eth_hdr,
307                 (struct ether_addr *)src_mac,
308                 (struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
309         pktlen = (uint16_t)(sizeof(struct ether_hdr));
310         printf("ETH  pktlen %u\n", pktlen);
311
312         pktlen = initialize_ipv4_header_proto(&pkt_ipv4_hdr, src_addr,
313                                         dst_addr, pktlen, IPPROTO_TCP);
314         printf("ETH + IPv4 pktlen %u\n", pktlen);
315
316         pktlen = initialize_tcp_header(&pkt_tcp_hdr, src_port, dst_port,
317                                         pktlen);
318         printf("ETH + IPv4 + TCP pktlen %u\n\n", pktlen);
319
320         return generate_packet_burst_proto(mp, pkts_burst, &pkt_eth_hdr,
321                                         0, &pkt_ipv4_hdr, 1, IPPROTO_TCP,
322                                         &pkt_tcp_hdr, burst_size,
323                                         PACKET_BURST_GEN_PKT_LEN, 1);
324 }
325
326 static int
327 init_ipv4_sctp_traffic(struct rte_mempool *mp,
328              struct rte_mbuf **pkts_burst, uint32_t burst_size)
329 {
330         struct ether_hdr pkt_eth_hdr;
331         struct ipv4_hdr pkt_ipv4_hdr;
332         struct sctp_hdr pkt_sctp_hdr;
333         uint32_t src_addr = IPV4_ADDR(11, 12, 13, 14);
334         uint32_t dst_addr = IPV4_ADDR(15, 16, 17, 18);
335         uint16_t src_port = 10;
336         uint16_t dst_port = 11;
337         uint16_t pktlen;
338
339         static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
340         static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
341
342         printf("Set up IPv4 SCTP traffic\n");
343         initialize_eth_header(&pkt_eth_hdr,
344                 (struct ether_addr *)src_mac,
345                 (struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
346         pktlen = (uint16_t)(sizeof(struct ether_hdr));
347         printf("ETH  pktlen %u\n", pktlen);
348
349         pktlen = initialize_ipv4_header_proto(&pkt_ipv4_hdr, src_addr,
350                                         dst_addr, pktlen, IPPROTO_SCTP);
351         printf("ETH + IPv4 pktlen %u\n", pktlen);
352
353         pktlen = initialize_sctp_header(&pkt_sctp_hdr, src_port, dst_port,
354                                         pktlen);
355         printf("ETH + IPv4 + SCTP pktlen %u\n\n", pktlen);
356
357         return generate_packet_burst_proto(mp, pkts_burst, &pkt_eth_hdr,
358                                         0, &pkt_ipv4_hdr, 1, IPPROTO_SCTP,
359                                         &pkt_sctp_hdr, burst_size,
360                                         PACKET_BURST_GEN_PKT_LEN, 1);
361 }
362
363 static int
364 init_mbufpool(void)
365 {
366         int socketid;
367         int ret = 0;
368         unsigned int lcore_id;
369         char s[64];
370
371         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
372                 if (rte_lcore_is_enabled(lcore_id) == 0)
373                         continue;
374
375                 socketid = rte_lcore_to_socket_id(lcore_id);
376                 if (socketid >= NB_SOCKETS) {
377                         printf(
378                                 "Socket %d of lcore %u is out of range %d\n",
379                                 socketid, lcore_id, NB_SOCKETS);
380                         ret = -1;
381                         break;
382                 }
383                 if (mbufpool[socketid] == NULL) {
384                         snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
385                         mbufpool[socketid] =
386                                 rte_pktmbuf_pool_create(s, NB_MBUF,
387                                         MEMPOOL_CACHE_SIZE, 0, MBUF_SIZE,
388                                         socketid);
389                         if (mbufpool[socketid]) {
390                                 printf("Allocated mbuf pool on socket %d\n",
391                                         socketid);
392                         } else {
393                                 printf("Cannot init mbuf pool on socket %d\n",
394                                         socketid);
395                                 ret = -ENOMEM;
396                                 break;
397                         }
398                 }
399         }
400         return ret;
401 }
402
403 static int
404 test_query_udp(void)
405 {
406         struct rte_flow_error error;
407         struct rte_flow_classify_rule *rule;
408         int ret;
409         int i;
410         int key_found;
411
412         ret = init_ipv4_udp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
413         if (ret != MAX_PKT_BURST) {
414                 printf("Line %i: init_udp_ipv4_traffic has failed!\n",
415                                 __LINE__);
416                 return -1;
417         }
418
419         for (i = 0; i < MAX_PKT_BURST; i++)
420                 bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
421
422         /*
423          * set up parameters for rte_flow_classify_table_entry_add and
424          * rte_flow_classify_table_entry_delete
425          */
426
427         attr.ingress = 1;
428         attr.priority = 1;
429         pattern[0] = eth_item;
430         pattern[1] = ipv4_udp_item_1;
431         pattern[2] = udp_item_1;
432         pattern[3] = end_item;
433         actions[0] = count_action;
434         actions[1] = end_action;
435
436         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
437                         &attr, pattern, actions, &error);
438         if (!rule) {
439                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
440                 printf(" should not have failed!\n");
441                 return -1;
442         }
443
444         ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
445                         rule, &udp_classify_stats);
446         if (ret) {
447                 printf("Line %i: flow_classifier_query", __LINE__);
448                 printf(" should not have failed!\n");
449                 return -1;
450         }
451
452         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
453         if (ret) {
454                 printf("Line %i: rte_flow_classify_table_entry_delete",
455                         __LINE__);
456                 printf(" should not have failed!\n");
457                 return -1;
458         }
459         return 0;
460 }
461
462 static int
463 test_query_tcp(void)
464 {
465         struct rte_flow_classify_rule *rule;
466         int ret;
467         int i;
468         int key_found;
469
470         ret = init_ipv4_tcp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
471         if (ret != MAX_PKT_BURST) {
472                 printf("Line %i: init_ipv4_tcp_traffic has failed!\n",
473                                 __LINE__);
474                 return -1;
475         }
476
477         for (i = 0; i < MAX_PKT_BURST; i++)
478                 bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
479
480         /*
481          * set up parameters for rte_flow_classify_table_entry_add and
482          * rte_flow_classify_table_entry_delete
483          */
484
485         attr.ingress = 1;
486         attr.priority = 1;
487         pattern[0] = eth_item;
488         pattern[1] = ipv4_tcp_item_1;
489         pattern[2] = tcp_item_1;
490         pattern[3] = end_item;
491         actions[0] = count_action;
492         actions[1] = end_action;
493
494         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
495                         &attr, pattern, actions, &error);
496         if (!rule) {
497                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
498                 printf(" should not have failed!\n");
499                 return -1;
500         }
501
502         ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
503                         rule, &tcp_classify_stats);
504         if (ret) {
505                 printf("Line %i: flow_classifier_query", __LINE__);
506                 printf(" should not have failed!\n");
507                 return -1;
508         }
509
510         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
511         if (ret) {
512                 printf("Line %i: rte_flow_classify_table_entry_delete",
513                         __LINE__);
514                 printf(" should not have failed!\n");
515                 return -1;
516         }
517         return 0;
518 }
519
520 static int
521 test_query_sctp(void)
522 {
523         struct rte_flow_classify_rule *rule;
524         int ret;
525         int i;
526         int key_found;
527
528         ret = init_ipv4_sctp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
529         if (ret != MAX_PKT_BURST) {
530                 printf("Line %i: init_ipv4_tcp_traffic has failed!\n",
531                         __LINE__);
532                 return -1;
533         }
534
535         for (i = 0; i < MAX_PKT_BURST; i++)
536                 bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
537
538         /*
539          * set up parameters rte_flow_classify_table_entry_add and
540          * rte_flow_classify_table_entry_delete
541          */
542
543         attr.ingress = 1;
544         attr.priority = 1;
545         pattern[0] = eth_item;
546         pattern[1] = ipv4_sctp_item_1;
547         pattern[2] = sctp_item_1;
548         pattern[3] = end_item;
549         actions[0] = count_action;
550         actions[1] = end_action;
551
552         rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
553                         &attr, pattern, actions, &error);
554         if (!rule) {
555                 printf("Line %i: flow_classify_table_entry_add", __LINE__);
556                 printf(" should not have failed!\n");
557                 return -1;
558         }
559
560         ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
561                         rule, &sctp_classify_stats);
562         if (ret) {
563                 printf("Line %i: flow_classifier_query", __LINE__);
564                 printf(" should not have failed!\n");
565                 return -1;
566         }
567
568         ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
569         if (ret) {
570                 printf("Line %i: rte_flow_classify_table_entry_delete",
571                         __LINE__);
572                 printf(" should not have failed!\n");
573                 return -1;
574         }
575         return 0;
576 }
577
578 static int
579 test_flow_classify(void)
580 {
581         struct rte_table_acl_params table_acl_params;
582         struct rte_flow_classify_table_params cls_table_params;
583         struct rte_flow_classifier_params cls_params;
584         int socket_id;
585         int ret;
586         uint32_t size;
587
588         socket_id = rte_eth_dev_socket_id(0);
589
590         /* Memory allocation */
591         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
592         cls = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
593
594         cls_params.name = "flow_classifier";
595         cls_params.socket_id = socket_id;
596         cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
597         cls->cls = rte_flow_classifier_create(&cls_params);
598
599         /* initialise ACL table params */
600         table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
601         table_acl_params.name = "table_acl_ipv4_5tuple";
602         table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
603         memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
604
605         /* initialise table create params */
606         cls_table_params.ops = &rte_table_acl_ops,
607         cls_table_params.arg_create = &table_acl_params,
608
609         ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
610                         &cls->table_id[0]);
611         if (ret) {
612                 printf("Line %i: f_create has failed!\n", __LINE__);
613                 rte_flow_classifier_free(cls->cls);
614                 rte_free(cls);
615                 return -1;
616         }
617         printf("Created table_acl for for IPv4 five tuple packets\n");
618
619         ret = init_mbufpool();
620         if (ret) {
621                 printf("Line %i: init_mbufpool has failed!\n", __LINE__);
622                 return -1;
623         }
624
625         if (test_invalid_parameters() < 0)
626                 return -1;
627         if (test_valid_parameters() < 0)
628                 return -1;
629         if (test_invalid_patterns() < 0)
630                 return -1;
631         if (test_invalid_actions() < 0)
632                 return -1;
633         if (test_query_udp() < 0)
634                 return -1;
635         if (test_query_tcp() < 0)
636                 return -1;
637         if (test_query_sctp() < 0)
638                 return -1;
639
640         return 0;
641 }
642
643 REGISTER_TEST_COMMAND(flow_classify_autotest, test_flow_classify);