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