tile: fix build
[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
402         test_kni_ctx = kni;
403         test_kni_processing_flag = 0;
404         stats.ingress = 0;
405         stats.egress = 0;
406
407         /**
408          * Check multiple processes support on
409          * registerring/unregisterring handlers.
410          */
411         if (test_kni_register_handler_mp() < 0) {
412                 printf("fail to check multiple process support\n");
413                 ret = -1;
414                 goto fail_kni;
415         }
416
417         rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
418         RTE_LCORE_FOREACH_SLAVE(i) {
419                 if (rte_eal_wait_lcore(i) < 0) {
420                         ret = -1;
421                         goto fail_kni;
422                 }
423         }
424         /**
425          * Check if the number of mbufs received from kernel space is equal
426          * to that of transmitted to kernel space
427          */
428         if (stats.ingress < KNI_NUM_MBUF_THRESHOLD ||
429                 stats.egress < KNI_NUM_MBUF_THRESHOLD) {
430                 printf("The ingress/egress number should not be "
431                         "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD);
432                 ret = -1;
433                 goto fail_kni;
434         }
435
436         if (rte_kni_release(kni) < 0) {
437                 printf("fail to release kni\n");
438                 return -1;
439         }
440         test_kni_ctx = NULL;
441
442         /* test of releasing a released kni device */
443         if (rte_kni_release(kni) == 0) {
444                 printf("should not release a released kni device\n");
445                 return -1;
446         }
447
448         /* test of reusing memzone */
449         kni = rte_kni_alloc(mp, &conf, &ops);
450         if (!kni) {
451                 printf("fail to create kni\n");
452                 return -1;
453         }
454
455         /* Release the kni for following testing */
456         if (rte_kni_release(kni) < 0) {
457                 printf("fail to release kni\n");
458                 return -1;
459         }
460
461         return ret;
462 fail_kni:
463         if (rte_kni_release(kni) < 0) {
464                 printf("fail to release kni\n");
465                 ret = -1;
466         }
467
468         return ret;
469 }
470
471 static int
472 test_kni(void)
473 {
474         int ret = -1;
475         uint8_t nb_ports, port_id;
476         struct rte_kni *kni;
477         struct rte_mempool *mp;
478         struct rte_kni_conf conf;
479         struct rte_eth_dev_info info;
480         struct rte_kni_ops ops;
481
482         /* Initialize KNI subsytem */
483         rte_kni_init(KNI_TEST_MAX_PORTS);
484
485         if (test_kni_allocate_lcores() < 0) {
486                 printf("No enough lcores for kni processing\n");
487                 return -1;
488         }
489
490         mp = test_kni_create_mempool();
491         if (!mp) {
492                 printf("fail to create mempool for kni\n");
493                 return -1;
494         }
495
496         nb_ports = rte_eth_dev_count();
497         if (nb_ports == 0) {
498                 printf("no supported nic port found\n");
499                 return -1;
500         }
501
502         /* configuring port 0 for the test is enough */
503         port_id = 0;
504         ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
505         if (ret < 0) {
506                 printf("fail to configure port %d\n", port_id);
507                 return -1;
508         }
509
510         ret = rte_eth_rx_queue_setup(port_id, 0, NB_RXD, SOCKET, &rx_conf, mp);
511         if (ret < 0) {
512                 printf("fail to setup rx queue for port %d\n", port_id);
513                 return -1;
514         }
515
516         ret = rte_eth_tx_queue_setup(port_id, 0, NB_TXD, SOCKET, &tx_conf);
517         if (ret < 0) {
518                 printf("fail to setup tx queue for port %d\n", port_id);
519                 return -1;
520         }
521
522         ret = rte_eth_dev_start(port_id);
523         if (ret < 0) {
524                 printf("fail to start port %d\n", port_id);
525                 return -1;
526         }
527         rte_eth_promiscuous_enable(port_id);
528
529         /* basic test of kni processing */
530         ret = test_kni_processing(port_id, mp);
531         if (ret < 0)
532                 goto fail;
533
534         /* test of allocating KNI with NULL mempool pointer */
535         memset(&info, 0, sizeof(info));
536         memset(&conf, 0, sizeof(conf));
537         memset(&ops, 0, sizeof(ops));
538         rte_eth_dev_info_get(port_id, &info);
539         conf.addr = info.pci_dev->addr;
540         conf.id = info.pci_dev->id;
541         conf.group_id = (uint16_t)port_id;
542         conf.mbuf_size = MAX_PACKET_SZ;
543
544         ops = kni_ops;
545         ops.port_id = port_id;
546         kni = rte_kni_alloc(NULL, &conf, &ops);
547         if (kni) {
548                 ret = -1;
549                 printf("unexpectedly creates kni successfully with NULL "
550                                                         "mempool pointer\n");
551                 goto fail;
552         }
553
554         /* test of allocating KNI without configurations */
555         kni = rte_kni_alloc(mp, NULL, NULL);
556         if (kni) {
557                 ret = -1;
558                 printf("Unexpectedly allocate KNI device successfully "
559                                         "without configurations\n");
560                 goto fail;
561         }
562
563         /* test of allocating KNI without a name */
564         memset(&conf, 0, sizeof(conf));
565         memset(&info, 0, sizeof(info));
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(mp, &conf, &ops);
576         if (kni) {
577                 ret = -1;
578                 printf("Unexpectedly allocate a KNI device successfully "
579                                                 "without a name\n");
580                 goto fail;
581         }
582
583         /* test of releasing NULL kni context */
584         ret = rte_kni_release(NULL);
585         if (ret == 0) {
586                 ret = -1;
587                 printf("unexpectedly release kni successfully\n");
588                 goto fail;
589         }
590
591         /* test of handling request on NULL device pointer */
592         ret = rte_kni_handle_request(NULL);
593         if (ret == 0) {
594                 ret = -1;
595                 printf("Unexpectedly handle request on NULL device pointer\n");
596                 goto fail;
597         }
598
599         /* test of getting KNI device with pointer to NULL */
600         kni = rte_kni_get(NULL);
601         if (kni) {
602                 ret = -1;
603                 printf("Unexpectedly get a KNI device with "
604                                         "NULL name pointer\n");
605                 goto fail;
606         }
607
608         /* test of getting KNI device with an zero length name string */
609         memset(&conf, 0, sizeof(conf));
610         kni = rte_kni_get(conf.name);
611         if (kni) {
612                 ret = -1;
613                 printf("Unexpectedly get a KNI device with "
614                                 "zero length name string\n");
615                 goto fail;
616         }
617
618         /* test of getting KNI device with an invalid string name */
619         memset(&conf, 0, sizeof(conf));
620         snprintf(conf.name, sizeof(conf.name), "testing");
621         kni = rte_kni_get(conf.name);
622         if (kni) {
623                 ret = -1;
624                 printf("Unexpectedly get a KNI device with "
625                                 "a never used name string\n");
626                 goto fail;
627         }
628         ret = 0;
629
630 fail:
631         rte_eth_dev_stop(port_id);
632
633         return ret;
634 }
635
636 REGISTER_TEST_COMMAND(kni_autotest, test_kni);