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