ethdev: make default behavior CRC strip on Rx
[dpdk.git] / test / test / test_kni.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <sys/wait.h>
10
11 #include "test.h"
12
13 #ifndef RTE_LIBRTE_KNI
14
15 static int
16 test_kni(void)
17 {
18         printf("KNI not supported, skipping test\n");
19         return TEST_SKIPPED;
20 }
21
22 #else
23
24 #include <rte_string_fns.h>
25 #include <rte_mempool.h>
26 #include <rte_ethdev.h>
27 #include <rte_bus_pci.h>
28 #include <rte_cycles.h>
29 #include <rte_kni.h>
30
31 #define NB_MBUF          8192
32 #define MAX_PACKET_SZ    2048
33 #define MBUF_DATA_SZ     (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM)
34 #define PKT_BURST_SZ     32
35 #define MEMPOOL_CACHE_SZ PKT_BURST_SZ
36 #define SOCKET           0
37 #define NB_RXD           1024
38 #define NB_TXD           1024
39 #define KNI_TIMEOUT_MS   5000 /* ms */
40
41 #define IFCONFIG      "/sbin/ifconfig "
42 #define TEST_KNI_PORT "test_kni_port"
43 #define KNI_TEST_MAX_PORTS 4
44 /* The threshold number of mbufs to be transmitted or received. */
45 #define KNI_NUM_MBUF_THRESHOLD 100
46 static int kni_pkt_mtu = 0;
47
48 struct test_kni_stats {
49         volatile uint64_t ingress;
50         volatile uint64_t egress;
51 };
52
53 static const struct rte_eth_rxconf rx_conf = {
54         .rx_thresh = {
55                 .pthresh = 8,
56                 .hthresh = 8,
57                 .wthresh = 4,
58         },
59         .rx_free_thresh = 0,
60 };
61
62 static const struct rte_eth_txconf tx_conf = {
63         .tx_thresh = {
64                 .pthresh = 36,
65                 .hthresh = 0,
66                 .wthresh = 0,
67         },
68         .tx_free_thresh = 0,
69         .tx_rs_thresh = 0,
70 };
71
72 static const struct rte_eth_conf port_conf = {
73         .txmode = {
74                 .mq_mode = ETH_DCB_NONE,
75         },
76 };
77
78 static struct rte_kni_ops kni_ops = {
79         .change_mtu = NULL,
80         .config_network_if = NULL,
81         .config_mac_address = NULL,
82         .config_promiscusity = NULL,
83 };
84
85 static unsigned lcore_master, lcore_ingress, lcore_egress;
86 static struct rte_kni *test_kni_ctx;
87 static struct test_kni_stats stats;
88
89 static volatile uint32_t test_kni_processing_flag;
90
91 static struct rte_mempool *
92 test_kni_create_mempool(void)
93 {
94         struct rte_mempool * mp;
95
96         mp = rte_mempool_lookup("kni_mempool");
97         if (!mp)
98                 mp = rte_pktmbuf_pool_create("kni_mempool",
99                                 NB_MBUF,
100                                 MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ,
101                                 SOCKET);
102
103         return mp;
104 }
105
106 static struct rte_mempool *
107 test_kni_lookup_mempool(void)
108 {
109         return rte_mempool_lookup("kni_mempool");
110 }
111 /* Callback for request of changing MTU */
112 static int
113 kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
114 {
115         printf("Change MTU of port %d to %u\n", port_id, new_mtu);
116         kni_pkt_mtu = new_mtu;
117         printf("Change MTU of port %d to %i successfully.\n",
118                                          port_id, kni_pkt_mtu);
119         return 0;
120 }
121 /**
122  * This loop fully tests the basic functions of KNI. e.g. transmitting,
123  * receiving to, from kernel space, and kernel requests.
124  *
125  * This is the loop to transmit/receive mbufs to/from kernel interface with
126  * supported by KNI kernel module. The ingress lcore will allocate mbufs and
127  * transmit them to kernel space; while the egress lcore will receive the mbufs
128  * from kernel space and free them.
129  * On the master lcore, several commands will be run to check handling the
130  * kernel requests. And it will finally set the flag to exit the KNI
131  * transmitting/receiving to/from the kernel space.
132  *
133  * Note: To support this testing, the KNI kernel module needs to be insmodded
134  * in one of its loopback modes.
135  */
136 static int
137 test_kni_loop(__rte_unused void *arg)
138 {
139         int ret = 0;
140         unsigned nb_rx, nb_tx, num, i;
141         const unsigned lcore_id = rte_lcore_id();
142         struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
143
144         if (lcore_id == lcore_master) {
145                 rte_delay_ms(KNI_TIMEOUT_MS);
146                 /* tests of handling kernel request */
147                 if (system(IFCONFIG TEST_KNI_PORT" up") == -1)
148                         ret = -1;
149                 if (system(IFCONFIG TEST_KNI_PORT" mtu 1400") == -1)
150                         ret = -1;
151                 if (system(IFCONFIG TEST_KNI_PORT" down") == -1)
152                         ret = -1;
153                 rte_delay_ms(KNI_TIMEOUT_MS);
154                 test_kni_processing_flag = 1;
155         } else if (lcore_id == lcore_ingress) {
156                 struct rte_mempool *mp = test_kni_lookup_mempool();
157
158                 if (mp == NULL)
159                         return -1;
160
161                 while (1) {
162                         if (test_kni_processing_flag)
163                                 break;
164
165                         for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) {
166                                 pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp);
167                                 if (!pkts_burst[nb_rx])
168                                         break;
169                         }
170
171                         num = rte_kni_tx_burst(test_kni_ctx, pkts_burst,
172                                                                 nb_rx);
173                         stats.ingress += num;
174                         rte_kni_handle_request(test_kni_ctx);
175                         if (num < nb_rx) {
176                                 for (i = num; i < nb_rx; i++) {
177                                         rte_pktmbuf_free(pkts_burst[i]);
178                                 }
179                         }
180                         rte_delay_ms(10);
181                 }
182         } else if (lcore_id == lcore_egress) {
183                 while (1) {
184                         if (test_kni_processing_flag)
185                                 break;
186                         num = rte_kni_rx_burst(test_kni_ctx, pkts_burst,
187                                                         PKT_BURST_SZ);
188                         stats.egress += num;
189                         for (nb_tx = 0; nb_tx < num; nb_tx++)
190                                 rte_pktmbuf_free(pkts_burst[nb_tx]);
191                         rte_delay_ms(10);
192                 }
193         }
194
195         return ret;
196 }
197
198 static int
199 test_kni_allocate_lcores(void)
200 {
201         unsigned i, count = 0;
202
203         lcore_master = rte_get_master_lcore();
204         printf("master lcore: %u\n", lcore_master);
205         for (i = 0; i < RTE_MAX_LCORE; i++) {
206                 if (count >=2 )
207                         break;
208                 if (rte_lcore_is_enabled(i) && i != lcore_master) {
209                         count ++;
210                         if (count == 1)
211                                 lcore_ingress = i;
212                         else if (count == 2)
213                                 lcore_egress = i;
214                 }
215         }
216         printf("count: %u\n", count);
217
218         return count == 2 ? 0 : -1;
219 }
220
221 static int
222 test_kni_register_handler_mp(void)
223 {
224 #define TEST_KNI_HANDLE_REQ_COUNT    10  /* 5s */
225 #define TEST_KNI_HANDLE_REQ_INTERVAL 500 /* ms */
226 #define TEST_KNI_MTU                 1450
227 #define TEST_KNI_MTU_STR             " 1450"
228         int pid;
229
230         pid = fork();
231         if (pid < 0) {
232                 printf("Failed to fork a process\n");
233                 return -1;
234         } else if (pid == 0) {
235                 int i;
236                 struct rte_kni *kni = rte_kni_get(TEST_KNI_PORT);
237                 struct rte_kni_ops ops = {
238                         .change_mtu = kni_change_mtu,
239                         .config_network_if = NULL,
240                         .config_mac_address = NULL,
241                         .config_promiscusity = NULL,
242                 };
243
244                 if (!kni) {
245                         printf("Failed to get KNI named %s\n", TEST_KNI_PORT);
246                         exit(-1);
247                 }
248
249                 kni_pkt_mtu = 0;
250
251                 /* Check with the invalid parameters */
252                 if (rte_kni_register_handlers(kni, NULL) == 0) {
253                         printf("Unexpectedly register successuflly "
254                                         "with NULL ops pointer\n");
255                         exit(-1);
256                 }
257                 if (rte_kni_register_handlers(NULL, &ops) == 0) {
258                         printf("Unexpectedly register successfully "
259                                         "to NULL KNI device pointer\n");
260                         exit(-1);
261                 }
262
263                 if (rte_kni_register_handlers(kni, &ops)) {
264                         printf("Fail to register ops\n");
265                         exit(-1);
266                 }
267
268                 /* Check registering again after it has been registered */
269                 if (rte_kni_register_handlers(kni, &ops) == 0) {
270                         printf("Unexpectedly register successfully after "
271                                         "it has already been registered\n");
272                         exit(-1);
273                 }
274
275                 /**
276                  * Handle the request of setting MTU,
277                  * with registered handlers.
278                  */
279                 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) {
280                         rte_kni_handle_request(kni);
281                         if (kni_pkt_mtu == TEST_KNI_MTU)
282                                 break;
283                         rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL);
284                 }
285                 if (i >= TEST_KNI_HANDLE_REQ_COUNT) {
286                         printf("MTU has not been set\n");
287                         exit(-1);
288                 }
289
290                 kni_pkt_mtu = 0;
291                 if (rte_kni_unregister_handlers(kni) < 0) {
292                         printf("Fail to unregister ops\n");
293                         exit(-1);
294                 }
295
296                 /* Check with invalid parameter */
297                 if (rte_kni_unregister_handlers(NULL) == 0) {
298                         exit(-1);
299                 }
300
301                 /**
302                  * Handle the request of setting MTU,
303                  * without registered handlers.
304                  */
305                 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) {
306                         rte_kni_handle_request(kni);
307                         if (kni_pkt_mtu != 0)
308                                 break;
309                         rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL);
310                 }
311                 if (kni_pkt_mtu != 0) {
312                         printf("MTU shouldn't be set\n");
313                         exit(-1);
314                 }
315
316                 exit(0);
317         } else {
318                 int p_ret, status;
319
320                 rte_delay_ms(1000);
321                 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR)
322                                                                 == -1)
323                         return -1;
324
325                 rte_delay_ms(1000);
326                 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR)
327                                                                 == -1)
328                         return -1;
329
330                 p_ret = wait(&status);
331                 if (!WIFEXITED(status)) {
332                         printf("Child process (%d) exit abnormally\n", p_ret);
333                         return -1;
334                 }
335                 if (WEXITSTATUS(status) != 0) {
336                         printf("Child process exit with failure\n");
337                         return -1;
338                 }
339         }
340
341         return 0;
342 }
343
344 static int
345 test_kni_processing(uint16_t port_id, struct rte_mempool *mp)
346 {
347         int ret = 0;
348         unsigned i;
349         struct rte_kni *kni;
350         struct rte_kni_conf conf;
351         struct rte_eth_dev_info info;
352         struct rte_kni_ops ops;
353         const struct rte_pci_device *pci_dev;
354         const struct rte_bus *bus = NULL;
355
356         if (!mp)
357                 return -1;
358
359         memset(&conf, 0, sizeof(conf));
360         memset(&info, 0, sizeof(info));
361         memset(&ops, 0, sizeof(ops));
362
363         rte_eth_dev_info_get(port_id, &info);
364         if (info.device)
365                 bus = rte_bus_find_by_device(info.device);
366         if (bus && !strcmp(bus->name, "pci")) {
367                 pci_dev = RTE_DEV_TO_PCI(info.device);
368                 conf.addr = pci_dev->addr;
369                 conf.id = pci_dev->id;
370         }
371         snprintf(conf.name, sizeof(conf.name), TEST_KNI_PORT);
372
373         /* core id 1 configured for kernel thread */
374         conf.core_id = 1;
375         conf.force_bind = 1;
376         conf.mbuf_size = MAX_PACKET_SZ;
377         conf.group_id = port_id;
378
379         ops = kni_ops;
380         ops.port_id = port_id;
381
382         /* basic test of kni processing */
383         kni = rte_kni_alloc(mp, &conf, &ops);
384         if (!kni) {
385                 printf("fail to create kni\n");
386                 return -1;
387         }
388
389         test_kni_ctx = kni;
390         test_kni_processing_flag = 0;
391         stats.ingress = 0;
392         stats.egress = 0;
393
394         /**
395          * Check multiple processes support on
396          * registerring/unregisterring handlers.
397          */
398         if (test_kni_register_handler_mp() < 0) {
399                 printf("fail to check multiple process support\n");
400                 ret = -1;
401                 goto fail_kni;
402         }
403
404         rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
405         RTE_LCORE_FOREACH_SLAVE(i) {
406                 if (rte_eal_wait_lcore(i) < 0) {
407                         ret = -1;
408                         goto fail_kni;
409                 }
410         }
411         /**
412          * Check if the number of mbufs received from kernel space is equal
413          * to that of transmitted to kernel space
414          */
415         if (stats.ingress < KNI_NUM_MBUF_THRESHOLD ||
416                 stats.egress < KNI_NUM_MBUF_THRESHOLD) {
417                 printf("The ingress/egress number should not be "
418                         "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD);
419                 ret = -1;
420                 goto fail_kni;
421         }
422
423         if (rte_kni_release(kni) < 0) {
424                 printf("fail to release kni\n");
425                 return -1;
426         }
427         test_kni_ctx = NULL;
428
429         /* test of releasing a released kni device */
430         if (rte_kni_release(kni) == 0) {
431                 printf("should not release a released kni device\n");
432                 return -1;
433         }
434
435         /* test of reusing memzone */
436         kni = rte_kni_alloc(mp, &conf, &ops);
437         if (!kni) {
438                 printf("fail to create kni\n");
439                 return -1;
440         }
441
442         /* Release the kni for following testing */
443         if (rte_kni_release(kni) < 0) {
444                 printf("fail to release kni\n");
445                 return -1;
446         }
447
448         return ret;
449 fail_kni:
450         if (rte_kni_release(kni) < 0) {
451                 printf("fail to release kni\n");
452                 ret = -1;
453         }
454
455         return ret;
456 }
457
458 static int
459 test_kni(void)
460 {
461         int ret = -1;
462         uint16_t nb_ports, port_id;
463         struct rte_kni *kni;
464         struct rte_mempool *mp;
465         struct rte_kni_conf conf;
466         struct rte_eth_dev_info info;
467         struct rte_kni_ops ops;
468         const struct rte_pci_device *pci_dev;
469         const struct rte_bus *bus;
470
471         /* Initialize KNI subsytem */
472         rte_kni_init(KNI_TEST_MAX_PORTS);
473
474         if (test_kni_allocate_lcores() < 0) {
475                 printf("No enough lcores for kni processing\n");
476                 return -1;
477         }
478
479         mp = test_kni_create_mempool();
480         if (!mp) {
481                 printf("fail to create mempool for kni\n");
482                 return -1;
483         }
484
485         nb_ports = rte_eth_dev_count_avail();
486         if (nb_ports == 0) {
487                 printf("no supported nic port found\n");
488                 return -1;
489         }
490
491         /* configuring port 0 for the test is enough */
492         port_id = 0;
493         ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
494         if (ret < 0) {
495                 printf("fail to configure port %d\n", port_id);
496                 return -1;
497         }
498
499         ret = rte_eth_rx_queue_setup(port_id, 0, NB_RXD, SOCKET, &rx_conf, mp);
500         if (ret < 0) {
501                 printf("fail to setup rx queue for port %d\n", port_id);
502                 return -1;
503         }
504
505         ret = rte_eth_tx_queue_setup(port_id, 0, NB_TXD, SOCKET, &tx_conf);
506         if (ret < 0) {
507                 printf("fail to setup tx queue for port %d\n", port_id);
508                 return -1;
509         }
510
511         ret = rte_eth_dev_start(port_id);
512         if (ret < 0) {
513                 printf("fail to start port %d\n", port_id);
514                 return -1;
515         }
516         rte_eth_promiscuous_enable(port_id);
517
518         /* basic test of kni processing */
519         ret = test_kni_processing(port_id, mp);
520         if (ret < 0)
521                 goto fail;
522
523         /* test of allocating KNI with NULL mempool pointer */
524         memset(&info, 0, sizeof(info));
525         memset(&conf, 0, sizeof(conf));
526         memset(&ops, 0, sizeof(ops));
527         rte_eth_dev_info_get(port_id, &info);
528         if (info.device)
529                 bus = rte_bus_find_by_device(info.device);
530         else
531                 bus = NULL;
532         if (bus && !strcmp(bus->name, "pci")) {
533                 pci_dev = RTE_DEV_TO_PCI(info.device);
534                 conf.addr = pci_dev->addr;
535                 conf.id = pci_dev->id;
536         }
537         conf.group_id = port_id;
538         conf.mbuf_size = MAX_PACKET_SZ;
539
540         ops = kni_ops;
541         ops.port_id = port_id;
542         kni = rte_kni_alloc(NULL, &conf, &ops);
543         if (kni) {
544                 ret = -1;
545                 printf("unexpectedly creates kni successfully with NULL "
546                                                         "mempool pointer\n");
547                 goto fail;
548         }
549
550         /* test of allocating KNI without configurations */
551         kni = rte_kni_alloc(mp, NULL, NULL);
552         if (kni) {
553                 ret = -1;
554                 printf("Unexpectedly allocate KNI device successfully "
555                                         "without configurations\n");
556                 goto fail;
557         }
558
559         /* test of allocating KNI without a name */
560         memset(&conf, 0, sizeof(conf));
561         memset(&info, 0, sizeof(info));
562         memset(&ops, 0, sizeof(ops));
563         rte_eth_dev_info_get(port_id, &info);
564         if (info.device)
565                 bus = rte_bus_find_by_device(info.device);
566         else
567                 bus = NULL;
568         if (bus && !strcmp(bus->name, "pci")) {
569                 pci_dev = RTE_DEV_TO_PCI(info.device);
570                 conf.addr = pci_dev->addr;
571                 conf.id = pci_dev->id;
572         }
573         conf.group_id = port_id;
574         conf.mbuf_size = MAX_PACKET_SZ;
575
576         ops = kni_ops;
577         ops.port_id = port_id;
578         kni = rte_kni_alloc(mp, &conf, &ops);
579         if (kni) {
580                 ret = -1;
581                 printf("Unexpectedly allocate a KNI device successfully "
582                                                 "without a name\n");
583                 goto fail;
584         }
585
586         /* test of releasing NULL kni context */
587         ret = rte_kni_release(NULL);
588         if (ret == 0) {
589                 ret = -1;
590                 printf("unexpectedly release kni successfully\n");
591                 goto fail;
592         }
593
594         /* test of handling request on NULL device pointer */
595         ret = rte_kni_handle_request(NULL);
596         if (ret == 0) {
597                 ret = -1;
598                 printf("Unexpectedly handle request on NULL device pointer\n");
599                 goto fail;
600         }
601
602         /* test of getting KNI device with pointer to NULL */
603         kni = rte_kni_get(NULL);
604         if (kni) {
605                 ret = -1;
606                 printf("Unexpectedly get a KNI device with "
607                                         "NULL name pointer\n");
608                 goto fail;
609         }
610
611         /* test of getting KNI device with an zero length name string */
612         memset(&conf, 0, sizeof(conf));
613         kni = rte_kni_get(conf.name);
614         if (kni) {
615                 ret = -1;
616                 printf("Unexpectedly get a KNI device with "
617                                 "zero length name string\n");
618                 goto fail;
619         }
620
621         /* test of getting KNI device with an invalid string name */
622         memset(&conf, 0, sizeof(conf));
623         snprintf(conf.name, sizeof(conf.name), "testing");
624         kni = rte_kni_get(conf.name);
625         if (kni) {
626                 ret = -1;
627                 printf("Unexpectedly get a KNI device with "
628                                 "a never used name string\n");
629                 goto fail;
630         }
631         ret = 0;
632
633 fail:
634         rte_eth_dev_stop(port_id);
635
636         return ret;
637 }
638
639 #endif
640
641 REGISTER_TEST_COMMAND(kni_autotest, test_kni);