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