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