doc: whitespace changes in licenses
[dpdk.git] / app / test / test_kni.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2013 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 <cmdline_parse.h>
41
42 #include "test.h"
43
44 #ifdef RTE_LIBRTE_KNI
45 #include <rte_mempool.h>
46 #include <rte_ethdev.h>
47 #include <rte_cycles.h>
48 #include <rte_kni.h>
49
50 #define NB_MBUF          (8192 * 16)
51 #define MAX_PACKET_SZ    2048
52 #define MBUF_SZ \
53         (MAX_PACKET_SZ + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
54 #define PKT_BURST_SZ     32
55 #define MEMPOOL_CACHE_SZ PKT_BURST_SZ
56 #define SOCKET           0
57 #define NB_RXD           128
58 #define NB_TXD           512
59 #define KNI_TIMEOUT_MS   5000 /* ms */
60
61 #define IFCONFIG "/sbin/ifconfig"
62
63 /* The threshold number of mbufs to be transmitted or received. */
64 #define KNI_NUM_MBUF_THRESHOLD 100
65 static int kni_pkt_mtu = 0;
66
67 struct test_kni_stats {
68         volatile uint64_t ingress;
69         volatile uint64_t egress;
70 };
71
72 static const struct rte_eth_rxconf rx_conf = {
73         .rx_thresh = {
74                 .pthresh = 8,
75                 .hthresh = 8,
76                 .wthresh = 4,
77         },
78         .rx_free_thresh = 0,
79 };
80
81 static const struct rte_eth_txconf tx_conf = {
82         .tx_thresh = {
83                 .pthresh = 36,
84                 .hthresh = 0,
85                 .wthresh = 0,
86         },
87         .tx_free_thresh = 0,
88         .tx_rs_thresh = 0,
89 };
90
91 static const struct rte_eth_conf port_conf = {
92         .rxmode = {
93                 .header_split = 0,
94                 .hw_ip_checksum = 0,
95                 .hw_vlan_filter = 0,
96                 .jumbo_frame = 0,
97                 .hw_strip_crc = 0,
98         },
99         .txmode = {
100                 .mq_mode = ETH_DCB_NONE,
101         },
102 };
103
104 static struct rte_kni_ops kni_ops = {
105         .change_mtu = NULL,
106         .config_network_if = NULL,
107 };
108
109 static unsigned lcore_master, lcore_ingress, lcore_egress;
110 static struct rte_kni *test_kni_ctx;
111 static struct test_kni_stats stats;
112
113 static volatile uint32_t test_kni_processing_flag;
114
115 static struct rte_mempool *
116 test_kni_create_mempool(void)
117 {
118         struct rte_mempool * mp;
119
120         mp = rte_mempool_lookup("kni_mempool");
121         if (!mp)
122                 mp = rte_mempool_create("kni_mempool",
123                                 NB_MBUF,
124                                 MBUF_SZ,
125                                 MEMPOOL_CACHE_SZ,
126                                 sizeof(struct rte_pktmbuf_pool_private),
127                                 rte_pktmbuf_pool_init,
128                                 NULL,
129                                 rte_pktmbuf_init,
130                                 NULL,
131                                 SOCKET,
132                                 0);
133
134         return mp;
135 }
136
137 static struct rte_mempool *
138 test_kni_lookup_mempool(void)
139 {
140         return rte_mempool_lookup("kni_mempool");
141 }
142 /* Callback for request of changing MTU */
143 static int
144 kni_change_mtu(uint8_t port_id, unsigned new_mtu)
145 {
146         printf("Change MTU of port %d to %u\n", port_id, new_mtu);
147         kni_pkt_mtu = new_mtu;  
148         printf("Change MTU of port %d to %i successfully.\n",
149                                          port_id, kni_pkt_mtu);
150         return 0;
151 }
152 /**
153  * This loop fully tests the basic functions of KNI. e.g. transmitting,
154  * receiving to, from kernel space, and kernel requests.
155  *
156  * This is the loop to transmit/receive mbufs to/from kernel interface with
157  * supported by KNI kernel module. The ingress lcore will allocate mbufs and
158  * transmit them to kernel space; while the egress lcore will receive the mbufs
159  * from kernel space and free them.
160  * On the master lcore, several commands will be run to check handling the
161  * kernel requests. And it will finally set the flag to exit the KNI
162  * transmitting/receiving to/from the kernel space.
163  *
164  * Note: To support this testing, the KNI kernel module needs to be insmodded
165  * in one of its loopback modes.
166  */
167 static int
168 test_kni_loop(__rte_unused void *arg)
169 {
170         int ret = 0;
171         unsigned nb_rx, nb_tx, num, i;
172         const unsigned lcore_id = rte_lcore_id();
173         struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
174
175         if (lcore_id == lcore_master) {
176                 rte_delay_ms(KNI_TIMEOUT_MS);
177                 /* tests of handling kernel request */
178                 if (system(IFCONFIG " vEth0 up") == -1)
179                         ret = -1;
180                 if (system(IFCONFIG " vEth0 mtu 1400") == -1)
181                         ret = -1;
182                 if (system(IFCONFIG " vEth0 down") == -1)
183                         ret = -1;
184                 rte_delay_ms(KNI_TIMEOUT_MS);
185                 test_kni_processing_flag = 1;
186         } else if (lcore_id == lcore_ingress) {
187                 struct rte_mempool *mp = test_kni_lookup_mempool();
188
189                 if (mp == NULL)
190                         return -1;
191
192                 while (1) {
193                         if (test_kni_processing_flag)
194                                 break;
195
196                         for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) {
197                                 pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp);
198                                 if (!pkts_burst[nb_rx])
199                                         break;
200                         }
201
202                         num = rte_kni_tx_burst(test_kni_ctx, pkts_burst,
203                                                                 nb_rx);
204                         stats.ingress += num;
205                         rte_kni_handle_request(test_kni_ctx);
206                         if (num < nb_rx) {
207                                 for (i = num; i < nb_rx; i++) {
208                                         rte_pktmbuf_free(pkts_burst[i]);
209                                 }
210                         }
211                 }
212         } else if (lcore_id == lcore_egress) {
213                 while (1) {
214                         if (test_kni_processing_flag)
215                                 break;
216                         num = rte_kni_rx_burst(test_kni_ctx, pkts_burst,
217                                                         PKT_BURST_SZ);
218                         stats.egress += num;
219                         for (nb_tx = 0; nb_tx < num; nb_tx++)
220                                 rte_pktmbuf_free(pkts_burst[nb_tx]);
221                 }
222         }
223
224         return ret;
225 }
226
227 static int
228 test_kni_allocate_lcores(void)
229 {
230         unsigned i, count = 0;
231
232         lcore_master = rte_get_master_lcore();
233         printf("master lcore: %u\n", lcore_master);
234         for (i = 0; i < RTE_MAX_LCORE; i++) {
235                 if (count >=2 )
236                         break;
237                 if (rte_lcore_is_enabled(i) && i != lcore_master) {
238                         count ++;
239                         if (count == 1)
240                                 lcore_ingress = i;
241                         else if (count == 2)
242                                 lcore_egress = i;
243                 }
244         }
245         printf("count: %u\n", count);
246
247         return (count == 2 ? 0 : -1);
248 }
249
250 static int
251 test_kni_processing(uint8_t pid, struct rte_mempool *mp)
252 {
253         int ret = 0;
254         unsigned i;
255         struct rte_kni *kni;
256         int p_id,p_ret;
257         int status;
258
259         if (!mp)
260                 return -1;
261
262         /* basic test of kni processing */
263         kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
264         if (!kni) {
265                 printf("fail to create kni\n");
266                 return -1;
267         }
268         if (rte_kni_get_port_id(kni) != pid) {
269                 printf("fail to get port id\n");
270                 ret = -1;
271                 goto fail_kni;
272         }
273
274         test_kni_ctx = kni;
275         test_kni_processing_flag = 0;
276         stats.ingress = 0;
277         stats.egress = 0;
278
279         /* create a subprocess to test the APIs of supporting multi-process */
280         p_id = fork();
281         if (p_id == 0) {
282                 struct rte_kni *kni_test;
283         #define TEST_MTU_SIZE  1450
284                 kni_test = rte_kni_info_get(RTE_MAX_ETHPORTS);
285                 if (kni_test) {
286                         printf("unexpectedly gets kni successfully with an invalid "
287                                                                         "port id\n");
288                         exit(-1);
289                 }
290                 kni_test = rte_kni_info_get(pid);
291                 if (NULL == kni_test) {
292                         printf("Failed to get KNI info of the port %d\n",pid);
293                         exit(-1);
294                 }
295                 struct rte_kni_ops kni_ops_test = {
296                         .change_mtu = kni_change_mtu,
297                         .config_network_if = NULL,
298                 };
299                 /* test of registering kni with NULL ops */     
300                 if (rte_kni_register_handlers(kni_test,NULL) == 0) {
301                         printf("unexpectedly register kni successfully"
302                                                 "with NULL ops\n");
303                         exit(-1);
304                 }
305                 if (rte_kni_register_handlers(kni_test,&kni_ops_test) < 0) {
306                         printf("Failed to register KNI request handler"
307                                                 "of the port %d\n",pid);
308                         exit(-1);
309                 }
310                 if (system(IFCONFIG " vEth0 mtu 1450") == -1) 
311                         exit(-1);
312                 
313                 rte_kni_handle_request(kni_test);
314                 if (kni_pkt_mtu != TEST_MTU_SIZE) {
315                         printf("Failed to change kni MTU\n");
316                         exit(-1) ;
317                 }
318
319                 /* test of unregistering kni request */
320                 kni_pkt_mtu = 0;
321                 if (rte_kni_unregister_handlers(kni_test) < 0) {
322                         printf("Failed to unregister kni request handlers\n");
323                         exit(-1);
324                 }
325                 if (system(IFCONFIG " vEth0 mtu 1450") == -1)
326                         exit(-1);
327
328                 rte_kni_handle_request(kni_test);
329                 if (kni_pkt_mtu != 0) {
330                         printf("Failed to test kni unregister handlers\n");
331                         exit(-1);               
332                 }
333                 exit(0);
334         }else if (p_id < 0) {
335                 printf("Failed to fork a process\n");
336                 return -1;
337         }else {
338                 p_ret = wait(&status);
339                 if (WIFEXITED(status)) 
340                         printf("test of multi-process api passed.\n");
341                 else {
342                         printf("KNI test:The child process %d exit abnormally./n",p_ret);
343                         return -1;
344                 }
345         }
346         rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
347         RTE_LCORE_FOREACH_SLAVE(i) {
348                 if (rte_eal_wait_lcore(i) < 0) {
349                         ret = -1;
350                         goto fail_kni;
351                 }
352         }
353         /**
354          * Check if the number of mbufs received from kernel space is equal
355          * to that of transmitted to kernel space
356          */
357         if (stats.ingress < KNI_NUM_MBUF_THRESHOLD ||
358                 stats.egress < KNI_NUM_MBUF_THRESHOLD) {
359                 printf("The ingress/egress number should not be "
360                         "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD);
361                 ret = -1;
362                 goto fail_kni;
363         }
364
365         /* test of creating kni on a port which has been used for a kni */
366         if (rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops) != NULL) {
367                 printf("should not create a kni successfully for a port which"
368                                                 "has been used for a kni\n");
369                 ret = -1;
370                 goto fail_kni;
371         }
372
373         if (rte_kni_release(kni) < 0) {
374                 printf("fail to release kni\n");
375                 return -1;
376         }
377         test_kni_ctx = NULL;
378         
379         /* test of releasing a released kni device */
380         if (rte_kni_release(kni) == 0) {
381                 printf("should not release a released kni device\n");
382                 return -1;
383         }
384
385         /* test of reusing memzone */
386         kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
387         if (!kni) {
388                 printf("fail to create kni\n");
389                 return -1;
390         }
391
392         /* Release the kni for following testing */
393         if (rte_kni_release(kni) < 0) {
394                 printf("fail to release kni\n");
395                 return -1;
396         }
397         
398         return ret;
399 fail_kni:
400         if (rte_kni_release(kni) < 0) {
401                 printf("fail to release kni\n");
402                 ret = -1;
403         }
404
405         return ret;
406 }
407
408 int
409 test_kni(void)
410 {
411         int ret = -1;
412         uint8_t nb_ports, pid;
413         struct rte_kni *kni;
414         struct rte_mempool * mp;
415
416         if (test_kni_allocate_lcores() < 0) {
417                 printf("No enough lcores for kni processing\n");
418                 return -1;
419         }
420
421         mp = test_kni_create_mempool();
422         if (!mp) {
423                 printf("fail to create mempool for kni\n");
424                 return -1;
425         }
426         ret = rte_pmd_init_all();
427         if (ret < 0) {
428                 printf("fail to initialize PMD\n");
429                 return -1;
430         }
431         ret = rte_eal_pci_probe();
432         if (ret < 0) {
433                 printf("fail to probe PCI devices\n");
434                 return -1;
435         }
436
437         nb_ports = rte_eth_dev_count();
438         if (nb_ports == 0) {
439                 printf("no supported nic port found\n");
440                 return -1;
441         }
442
443         /* configuring port 0 for the test is enough */
444         pid = 0;
445         ret = rte_eth_dev_configure(pid, 1, 1, &port_conf);
446         if (ret < 0) {
447                 printf("fail to configure port %d\n", pid);
448                 return -1;
449         }
450
451         ret = rte_eth_rx_queue_setup(pid, 0, NB_RXD, SOCKET, &rx_conf, mp);
452         if (ret < 0) {
453                 printf("fail to setup rx queue for port %d\n", pid);
454                 return -1;
455         }
456
457         ret = rte_eth_tx_queue_setup(pid, 0, NB_TXD, SOCKET, &tx_conf);
458         if (ret < 0) {
459                 printf("fail to setup tx queue for port %d\n", pid);
460                 return -1;
461         }
462
463         ret = rte_eth_dev_start(pid);
464         if (ret < 0) {
465                 printf("fail to start port %d\n", pid);
466                 return -1;
467         }
468
469         rte_eth_promiscuous_enable(pid);
470
471         /* basic test of kni processing */
472         ret = test_kni_processing(pid, mp);
473         if (ret < 0)
474                 goto fail;
475
476         /* test of creating kni with port id exceeds the maximum */
477         kni = rte_kni_create(RTE_MAX_ETHPORTS, MAX_PACKET_SZ, mp, &kni_ops);
478         if (kni) {
479                 printf("unexpectedly creates kni successfully with an invalid "
480                                                                 "port id\n");
481                 goto fail;
482         }
483
484         /* test of creating kni with NULL mempool pointer */
485         kni = rte_kni_create(pid, MAX_PACKET_SZ, NULL, &kni_ops);
486         if (kni) {
487                 printf("unexpectedly creates kni successfully with NULL "
488                                                         "mempool pointer\n");
489                 goto fail;
490         }
491
492         /* test of creating kni with NULL ops */
493         kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, NULL);
494         if (!kni) { 
495                 printf("unexpectedly creates kni falied with NULL ops\n");
496                 goto fail;
497         }
498
499         /* test of releasing kni with NULL ops */
500         if (rte_kni_release(kni) < 0) {
501                 printf("fail to release kni\n");
502                 goto fail;
503         }       
504
505         /* test of getting port id according to NULL kni context */
506         if (rte_kni_get_port_id(NULL) < RTE_MAX_ETHPORTS) {
507                 printf("unexpectedly get port id successfully by NULL kni "
508                                                                 "pointer\n");
509                 goto fail;
510         }
511
512         /* test of releasing NULL kni context */
513         ret = rte_kni_release(NULL);
514         if (ret == 0) {
515                 printf("unexpectedly release kni successfully\n");
516                 goto fail;
517         }
518
519         ret = 0;
520
521 fail:
522         rte_eth_dev_stop(pid);
523
524         return ret;
525 }
526
527 #else /* RTE_LIBRTE_KNI */
528
529 int
530 test_kni(void)
531 {
532         printf("The KNI library is not included in this build\n");
533         return 0;
534 }
535
536 #endif /* RTE_LIBRTE_KNI */