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