kni: add function to set link state on kernel interface
[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 static int
123 test_kni_link_change(void)
124 {
125         int ret;
126         int pid;
127
128         pid = fork();
129         if (pid < 0) {
130                 printf("Error: Failed to fork a process\n");
131                 return -1;
132         }
133
134         if (pid == 0) {
135                 printf("Starting KNI Link status change tests.\n");
136                 if (system(IFCONFIG TEST_KNI_PORT" up") == -1) {
137                         ret = -1;
138                         goto error;
139                 }
140
141                 ret = rte_kni_update_link(test_kni_ctx, 1);
142                 if (ret < 0) {
143                         printf("Failed to change link state to Up ret=%d.\n",
144                                 ret);
145                         goto error;
146                 }
147                 rte_delay_ms(1000);
148                 printf("KNI: Set LINKUP, previous state=%d\n", ret);
149
150                 ret = rte_kni_update_link(test_kni_ctx, 0);
151                 if (ret != 1) {
152                         printf(
153                 "Failed! Previous link state should be 1, returned %d.\n",
154                                 ret);
155                         goto error;
156                 }
157                 rte_delay_ms(1000);
158                 printf("KNI: Set LINKDOWN, previous state=%d\n", ret);
159
160                 ret = rte_kni_update_link(test_kni_ctx, 1);
161                 if (ret != 0) {
162                         printf(
163                 "Failed! Previous link state should be 0, returned %d.\n",
164                                 ret);
165                         goto error;
166                 }
167                 printf("KNI: Set LINKUP, previous state=%d\n", ret);
168
169                 ret = 0;
170                 rte_delay_ms(1000);
171
172 error:
173                 if (system(IFCONFIG TEST_KNI_PORT" down") == -1)
174                         ret = -1;
175
176                 printf("KNI: Link status change tests: %s.\n",
177                         (ret == 0) ? "Passed" : "Failed");
178                 exit(ret);
179         } else {
180                 int p_ret, status;
181
182                 while (1) {
183                         p_ret = waitpid(pid, &status, WNOHANG);
184                         if (p_ret != 0) {
185                                 if (WIFEXITED(status))
186                                         return WEXITSTATUS(status);
187                                 return -1;
188                         }
189                         rte_delay_ms(10);
190                         rte_kni_handle_request(test_kni_ctx);
191                 }
192         }
193 }
194 /**
195  * This loop fully tests the basic functions of KNI. e.g. transmitting,
196  * receiving to, from kernel space, and kernel requests.
197  *
198  * This is the loop to transmit/receive mbufs to/from kernel interface with
199  * supported by KNI kernel module. The ingress lcore will allocate mbufs and
200  * transmit them to kernel space; while the egress lcore will receive the mbufs
201  * from kernel space and free them.
202  * On the master lcore, several commands will be run to check handling the
203  * kernel requests. And it will finally set the flag to exit the KNI
204  * transmitting/receiving to/from the kernel space.
205  *
206  * Note: To support this testing, the KNI kernel module needs to be insmodded
207  * in one of its loopback modes.
208  */
209 static int
210 test_kni_loop(__rte_unused void *arg)
211 {
212         int ret = 0;
213         unsigned nb_rx, nb_tx, num, i;
214         const unsigned lcore_id = rte_lcore_id();
215         struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
216
217         if (lcore_id == lcore_master) {
218                 rte_delay_ms(KNI_TIMEOUT_MS);
219                 /* tests of handling kernel request */
220                 if (system(IFCONFIG TEST_KNI_PORT" up") == -1)
221                         ret = -1;
222                 if (system(IFCONFIG TEST_KNI_PORT" mtu 1400") == -1)
223                         ret = -1;
224                 if (system(IFCONFIG TEST_KNI_PORT" down") == -1)
225                         ret = -1;
226                 rte_delay_ms(KNI_TIMEOUT_MS);
227                 test_kni_processing_flag = 1;
228         } else if (lcore_id == lcore_ingress) {
229                 struct rte_mempool *mp = test_kni_lookup_mempool();
230
231                 if (mp == NULL)
232                         return -1;
233
234                 while (1) {
235                         if (test_kni_processing_flag)
236                                 break;
237
238                         for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) {
239                                 pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp);
240                                 if (!pkts_burst[nb_rx])
241                                         break;
242                         }
243
244                         num = rte_kni_tx_burst(test_kni_ctx, pkts_burst,
245                                                                 nb_rx);
246                         stats.ingress += num;
247                         rte_kni_handle_request(test_kni_ctx);
248                         if (num < nb_rx) {
249                                 for (i = num; i < nb_rx; i++) {
250                                         rte_pktmbuf_free(pkts_burst[i]);
251                                 }
252                         }
253                         rte_delay_ms(10);
254                 }
255         } else if (lcore_id == lcore_egress) {
256                 while (1) {
257                         if (test_kni_processing_flag)
258                                 break;
259                         num = rte_kni_rx_burst(test_kni_ctx, pkts_burst,
260                                                         PKT_BURST_SZ);
261                         stats.egress += num;
262                         for (nb_tx = 0; nb_tx < num; nb_tx++)
263                                 rte_pktmbuf_free(pkts_burst[nb_tx]);
264                         rte_delay_ms(10);
265                 }
266         }
267
268         return ret;
269 }
270
271 static int
272 test_kni_allocate_lcores(void)
273 {
274         unsigned i, count = 0;
275
276         lcore_master = rte_get_master_lcore();
277         printf("master lcore: %u\n", lcore_master);
278         for (i = 0; i < RTE_MAX_LCORE; i++) {
279                 if (count >=2 )
280                         break;
281                 if (rte_lcore_is_enabled(i) && i != lcore_master) {
282                         count ++;
283                         if (count == 1)
284                                 lcore_ingress = i;
285                         else if (count == 2)
286                                 lcore_egress = i;
287                 }
288         }
289         printf("count: %u\n", count);
290
291         return count == 2 ? 0 : -1;
292 }
293
294 static int
295 test_kni_register_handler_mp(void)
296 {
297 #define TEST_KNI_HANDLE_REQ_COUNT    10  /* 5s */
298 #define TEST_KNI_HANDLE_REQ_INTERVAL 500 /* ms */
299 #define TEST_KNI_MTU                 1450
300 #define TEST_KNI_MTU_STR             " 1450"
301         int pid;
302
303         pid = fork();
304         if (pid < 0) {
305                 printf("Failed to fork a process\n");
306                 return -1;
307         } else if (pid == 0) {
308                 int i;
309                 struct rte_kni *kni = rte_kni_get(TEST_KNI_PORT);
310                 struct rte_kni_ops ops = {
311                         .change_mtu = kni_change_mtu,
312                         .config_network_if = NULL,
313                         .config_mac_address = NULL,
314                         .config_promiscusity = NULL,
315                 };
316
317                 if (!kni) {
318                         printf("Failed to get KNI named %s\n", TEST_KNI_PORT);
319                         exit(-1);
320                 }
321
322                 kni_pkt_mtu = 0;
323
324                 /* Check with the invalid parameters */
325                 if (rte_kni_register_handlers(kni, NULL) == 0) {
326                         printf("Unexpectedly register successuflly "
327                                         "with NULL ops pointer\n");
328                         exit(-1);
329                 }
330                 if (rte_kni_register_handlers(NULL, &ops) == 0) {
331                         printf("Unexpectedly register successfully "
332                                         "to NULL KNI device pointer\n");
333                         exit(-1);
334                 }
335
336                 if (rte_kni_register_handlers(kni, &ops)) {
337                         printf("Fail to register ops\n");
338                         exit(-1);
339                 }
340
341                 /* Check registering again after it has been registered */
342                 if (rte_kni_register_handlers(kni, &ops) == 0) {
343                         printf("Unexpectedly register successfully after "
344                                         "it has already been registered\n");
345                         exit(-1);
346                 }
347
348                 /**
349                  * Handle the request of setting MTU,
350                  * with registered handlers.
351                  */
352                 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) {
353                         rte_kni_handle_request(kni);
354                         if (kni_pkt_mtu == TEST_KNI_MTU)
355                                 break;
356                         rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL);
357                 }
358                 if (i >= TEST_KNI_HANDLE_REQ_COUNT) {
359                         printf("MTU has not been set\n");
360                         exit(-1);
361                 }
362
363                 kni_pkt_mtu = 0;
364                 if (rte_kni_unregister_handlers(kni) < 0) {
365                         printf("Fail to unregister ops\n");
366                         exit(-1);
367                 }
368
369                 /* Check with invalid parameter */
370                 if (rte_kni_unregister_handlers(NULL) == 0) {
371                         exit(-1);
372                 }
373
374                 /**
375                  * Handle the request of setting MTU,
376                  * without registered handlers.
377                  */
378                 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) {
379                         rte_kni_handle_request(kni);
380                         if (kni_pkt_mtu != 0)
381                                 break;
382                         rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL);
383                 }
384                 if (kni_pkt_mtu != 0) {
385                         printf("MTU shouldn't be set\n");
386                         exit(-1);
387                 }
388
389                 exit(0);
390         } else {
391                 int p_ret, status;
392
393                 rte_delay_ms(1000);
394                 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR)
395                                                                 == -1)
396                         return -1;
397
398                 rte_delay_ms(1000);
399                 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR)
400                                                                 == -1)
401                         return -1;
402
403                 p_ret = wait(&status);
404                 if (!WIFEXITED(status)) {
405                         printf("Child process (%d) exit abnormally\n", p_ret);
406                         return -1;
407                 }
408                 if (WEXITSTATUS(status) != 0) {
409                         printf("Child process exit with failure\n");
410                         return -1;
411                 }
412         }
413
414         return 0;
415 }
416
417 static int
418 test_kni_processing(uint16_t port_id, struct rte_mempool *mp)
419 {
420         int ret = 0;
421         unsigned i;
422         struct rte_kni *kni;
423         struct rte_kni_conf conf;
424         struct rte_eth_dev_info info;
425         struct rte_kni_ops ops;
426         const struct rte_pci_device *pci_dev;
427         const struct rte_bus *bus = NULL;
428
429         if (!mp)
430                 return -1;
431
432         memset(&conf, 0, sizeof(conf));
433         memset(&info, 0, sizeof(info));
434         memset(&ops, 0, sizeof(ops));
435
436         rte_eth_dev_info_get(port_id, &info);
437         if (info.device)
438                 bus = rte_bus_find_by_device(info.device);
439         if (bus && !strcmp(bus->name, "pci")) {
440                 pci_dev = RTE_DEV_TO_PCI(info.device);
441                 conf.addr = pci_dev->addr;
442                 conf.id = pci_dev->id;
443         }
444         snprintf(conf.name, sizeof(conf.name), TEST_KNI_PORT);
445
446         /* core id 1 configured for kernel thread */
447         conf.core_id = 1;
448         conf.force_bind = 1;
449         conf.mbuf_size = MAX_PACKET_SZ;
450         conf.group_id = port_id;
451
452         ops = kni_ops;
453         ops.port_id = port_id;
454
455         /* basic test of kni processing */
456         kni = rte_kni_alloc(mp, &conf, &ops);
457         if (!kni) {
458                 printf("fail to create kni\n");
459                 return -1;
460         }
461
462         test_kni_ctx = kni;
463         test_kni_processing_flag = 0;
464         stats.ingress = 0;
465         stats.egress = 0;
466
467         /**
468          * Check multiple processes support on
469          * registerring/unregisterring handlers.
470          */
471         if (test_kni_register_handler_mp() < 0) {
472                 printf("fail to check multiple process support\n");
473                 ret = -1;
474                 goto fail_kni;
475         }
476
477         ret = test_kni_link_change();
478         if (ret != 0)
479                 goto fail_kni;
480
481         rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
482         RTE_LCORE_FOREACH_SLAVE(i) {
483                 if (rte_eal_wait_lcore(i) < 0) {
484                         ret = -1;
485                         goto fail_kni;
486                 }
487         }
488         /**
489          * Check if the number of mbufs received from kernel space is equal
490          * to that of transmitted to kernel space
491          */
492         if (stats.ingress < KNI_NUM_MBUF_THRESHOLD ||
493                 stats.egress < KNI_NUM_MBUF_THRESHOLD) {
494                 printf("The ingress/egress number should not be "
495                         "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD);
496                 ret = -1;
497                 goto fail_kni;
498         }
499
500         if (rte_kni_release(kni) < 0) {
501                 printf("fail to release kni\n");
502                 return -1;
503         }
504         test_kni_ctx = NULL;
505
506         /* test of reusing memzone */
507         kni = rte_kni_alloc(mp, &conf, &ops);
508         if (!kni) {
509                 printf("fail to create kni\n");
510                 return -1;
511         }
512
513         /* Release the kni for following testing */
514         if (rte_kni_release(kni) < 0) {
515                 printf("fail to release kni\n");
516                 return -1;
517         }
518
519         return ret;
520 fail_kni:
521         if (rte_kni_release(kni) < 0) {
522                 printf("fail to release kni\n");
523                 ret = -1;
524         }
525
526         return ret;
527 }
528
529 static int
530 test_kni(void)
531 {
532         int ret = -1;
533         uint16_t nb_ports, port_id;
534         struct rte_kni *kni;
535         struct rte_mempool *mp;
536         struct rte_kni_conf conf;
537         struct rte_eth_dev_info info;
538         struct rte_kni_ops ops;
539         const struct rte_pci_device *pci_dev;
540         const struct rte_bus *bus;
541
542         /* Initialize KNI subsytem */
543         rte_kni_init(KNI_TEST_MAX_PORTS);
544
545         if (test_kni_allocate_lcores() < 0) {
546                 printf("No enough lcores for kni processing\n");
547                 return -1;
548         }
549
550         mp = test_kni_create_mempool();
551         if (!mp) {
552                 printf("fail to create mempool for kni\n");
553                 return -1;
554         }
555
556         nb_ports = rte_eth_dev_count_avail();
557         if (nb_ports == 0) {
558                 printf("no supported nic port found\n");
559                 return -1;
560         }
561
562         /* configuring port 0 for the test is enough */
563         port_id = 0;
564         ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
565         if (ret < 0) {
566                 printf("fail to configure port %d\n", port_id);
567                 return -1;
568         }
569
570         ret = rte_eth_rx_queue_setup(port_id, 0, NB_RXD, SOCKET, &rx_conf, mp);
571         if (ret < 0) {
572                 printf("fail to setup rx queue for port %d\n", port_id);
573                 return -1;
574         }
575
576         ret = rte_eth_tx_queue_setup(port_id, 0, NB_TXD, SOCKET, &tx_conf);
577         if (ret < 0) {
578                 printf("fail to setup tx queue for port %d\n", port_id);
579                 return -1;
580         }
581
582         ret = rte_eth_dev_start(port_id);
583         if (ret < 0) {
584                 printf("fail to start port %d\n", port_id);
585                 return -1;
586         }
587         rte_eth_promiscuous_enable(port_id);
588
589         /* basic test of kni processing */
590         ret = test_kni_processing(port_id, mp);
591         if (ret < 0)
592                 goto fail;
593
594         /* test of allocating KNI with NULL mempool pointer */
595         memset(&info, 0, sizeof(info));
596         memset(&conf, 0, sizeof(conf));
597         memset(&ops, 0, sizeof(ops));
598         rte_eth_dev_info_get(port_id, &info);
599         if (info.device)
600                 bus = rte_bus_find_by_device(info.device);
601         else
602                 bus = NULL;
603         if (bus && !strcmp(bus->name, "pci")) {
604                 pci_dev = RTE_DEV_TO_PCI(info.device);
605                 conf.addr = pci_dev->addr;
606                 conf.id = pci_dev->id;
607         }
608         conf.group_id = port_id;
609         conf.mbuf_size = MAX_PACKET_SZ;
610
611         ops = kni_ops;
612         ops.port_id = port_id;
613         kni = rte_kni_alloc(NULL, &conf, &ops);
614         if (kni) {
615                 ret = -1;
616                 printf("unexpectedly creates kni successfully with NULL "
617                                                         "mempool pointer\n");
618                 goto fail;
619         }
620
621         /* test of allocating KNI without configurations */
622         kni = rte_kni_alloc(mp, NULL, NULL);
623         if (kni) {
624                 ret = -1;
625                 printf("Unexpectedly allocate KNI device successfully "
626                                         "without configurations\n");
627                 goto fail;
628         }
629
630         /* test of allocating KNI without a name */
631         memset(&conf, 0, sizeof(conf));
632         memset(&info, 0, sizeof(info));
633         memset(&ops, 0, sizeof(ops));
634         rte_eth_dev_info_get(port_id, &info);
635         if (info.device)
636                 bus = rte_bus_find_by_device(info.device);
637         else
638                 bus = NULL;
639         if (bus && !strcmp(bus->name, "pci")) {
640                 pci_dev = RTE_DEV_TO_PCI(info.device);
641                 conf.addr = pci_dev->addr;
642                 conf.id = pci_dev->id;
643         }
644         conf.group_id = port_id;
645         conf.mbuf_size = MAX_PACKET_SZ;
646
647         ops = kni_ops;
648         ops.port_id = port_id;
649         kni = rte_kni_alloc(mp, &conf, &ops);
650         if (kni) {
651                 ret = -1;
652                 printf("Unexpectedly allocate a KNI device successfully "
653                                                 "without a name\n");
654                 goto fail;
655         }
656
657         /* test of releasing NULL kni context */
658         ret = rte_kni_release(NULL);
659         if (ret == 0) {
660                 ret = -1;
661                 printf("unexpectedly release kni successfully\n");
662                 goto fail;
663         }
664
665         /* test of handling request on NULL device pointer */
666         ret = rte_kni_handle_request(NULL);
667         if (ret == 0) {
668                 ret = -1;
669                 printf("Unexpectedly handle request on NULL device pointer\n");
670                 goto fail;
671         }
672
673         /* test of getting KNI device with pointer to NULL */
674         kni = rte_kni_get(NULL);
675         if (kni) {
676                 ret = -1;
677                 printf("Unexpectedly get a KNI device with "
678                                         "NULL name pointer\n");
679                 goto fail;
680         }
681
682         /* test of getting KNI device with an zero length name string */
683         memset(&conf, 0, sizeof(conf));
684         kni = rte_kni_get(conf.name);
685         if (kni) {
686                 ret = -1;
687                 printf("Unexpectedly get a KNI device with "
688                                 "zero length name string\n");
689                 goto fail;
690         }
691
692         /* test of getting KNI device with an invalid string name */
693         memset(&conf, 0, sizeof(conf));
694         snprintf(conf.name, sizeof(conf.name), "testing");
695         kni = rte_kni_get(conf.name);
696         if (kni) {
697                 ret = -1;
698                 printf("Unexpectedly get a KNI device with "
699                                 "a never used name string\n");
700                 goto fail;
701         }
702         ret = 0;
703
704 fail:
705         rte_eth_dev_stop(port_id);
706
707         return ret;
708 }
709
710 #endif
711
712 REGISTER_TEST_COMMAND(kni_autotest, test_kni);