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