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