4 * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
41 #include <cmdline_parse.h>
46 #include <rte_mempool.h>
47 #include <rte_ethdev.h>
48 #include <rte_cycles.h>
51 #define NB_MBUF (8192 * 16)
52 #define MAX_PACKET_SZ 2048
54 (MAX_PACKET_SZ + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
55 #define PKT_BURST_SZ 32
56 #define MEMPOOL_CACHE_SZ PKT_BURST_SZ
60 #define KNI_TIMEOUT_MS 5000 /* ms */
62 #define IFCONFIG "/sbin/ifconfig"
64 /* The threshold number of mbufs to be transmitted or received. */
65 #define KNI_NUM_MBUF_THRESHOLD 100
66 static int kni_pkt_mtu = 0;
68 struct test_kni_stats {
69 volatile uint64_t ingress;
70 volatile uint64_t egress;
73 static const struct rte_eth_rxconf rx_conf = {
82 static const struct rte_eth_txconf tx_conf = {
92 static const struct rte_eth_conf port_conf = {
101 .mq_mode = ETH_DCB_NONE,
105 static struct rte_kni_ops kni_ops = {
107 .config_network_if = NULL,
110 static unsigned lcore_master, lcore_ingress, lcore_egress;
111 static struct rte_kni *test_kni_ctx;
112 static struct test_kni_stats stats;
114 static volatile uint32_t test_kni_processing_flag;
116 static struct rte_mempool *
117 test_kni_create_mempool(void)
119 struct rte_mempool * mp;
121 mp = rte_mempool_lookup("kni_mempool");
123 mp = rte_mempool_create("kni_mempool",
127 sizeof(struct rte_pktmbuf_pool_private),
128 rte_pktmbuf_pool_init,
138 static struct rte_mempool *
139 test_kni_lookup_mempool(void)
141 return rte_mempool_lookup("kni_mempool");
143 /* Callback for request of changing MTU */
145 kni_change_mtu(uint8_t port_id, unsigned new_mtu)
147 printf("Change MTU of port %d to %u\n", port_id, new_mtu);
148 kni_pkt_mtu = new_mtu;
149 printf("Change MTU of port %d to %i successfully.\n",
150 port_id, kni_pkt_mtu);
154 * This loop fully tests the basic functions of KNI. e.g. transmitting,
155 * receiving to, from kernel space, and kernel requests.
157 * This is the loop to transmit/receive mbufs to/from kernel interface with
158 * supported by KNI kernel module. The ingress lcore will allocate mbufs and
159 * transmit them to kernel space; while the egress lcore will receive the mbufs
160 * from kernel space and free them.
161 * On the master lcore, several commands will be run to check handling the
162 * kernel requests. And it will finally set the flag to exit the KNI
163 * transmitting/receiving to/from the kernel space.
165 * Note: To support this testing, the KNI kernel module needs to be insmodded
166 * in one of its loopback modes.
169 test_kni_loop(__rte_unused void *arg)
172 unsigned nb_rx, nb_tx, num, i;
173 const unsigned lcore_id = rte_lcore_id();
174 struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
176 if (lcore_id == lcore_master) {
177 rte_delay_ms(KNI_TIMEOUT_MS);
178 /* tests of handling kernel request */
179 if (system(IFCONFIG " vEth0 up") == -1)
181 if (system(IFCONFIG " vEth0 mtu 1400") == -1)
183 if (system(IFCONFIG " vEth0 down") == -1)
185 rte_delay_ms(KNI_TIMEOUT_MS);
186 test_kni_processing_flag = 1;
187 } else if (lcore_id == lcore_ingress) {
188 struct rte_mempool *mp = test_kni_lookup_mempool();
194 if (test_kni_processing_flag)
197 for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) {
198 pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp);
199 if (!pkts_burst[nb_rx])
203 num = rte_kni_tx_burst(test_kni_ctx, pkts_burst,
205 stats.ingress += num;
206 rte_kni_handle_request(test_kni_ctx);
208 for (i = num; i < nb_rx; i++) {
209 rte_pktmbuf_free(pkts_burst[i]);
213 } else if (lcore_id == lcore_egress) {
215 if (test_kni_processing_flag)
217 num = rte_kni_rx_burst(test_kni_ctx, pkts_burst,
220 for (nb_tx = 0; nb_tx < num; nb_tx++)
221 rte_pktmbuf_free(pkts_burst[nb_tx]);
229 test_kni_allocate_lcores(void)
231 unsigned i, count = 0;
233 lcore_master = rte_get_master_lcore();
234 printf("master lcore: %u\n", lcore_master);
235 for (i = 0; i < RTE_MAX_LCORE; i++) {
238 if (rte_lcore_is_enabled(i) && i != lcore_master) {
246 printf("count: %u\n", count);
248 return (count == 2 ? 0 : -1);
252 test_kni_processing(uint8_t pid, struct rte_mempool *mp)
263 /* basic test of kni processing */
264 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
266 printf("fail to create kni\n");
269 if (rte_kni_get_port_id(kni) != pid) {
270 printf("fail to get port id\n");
276 test_kni_processing_flag = 0;
280 /* create a subprocess to test the APIs of supporting multi-process */
283 struct rte_kni *kni_test;
284 #define TEST_MTU_SIZE 1450
285 kni_test = rte_kni_info_get(RTE_MAX_ETHPORTS);
287 printf("unexpectedly gets kni successfully with an invalid "
291 kni_test = rte_kni_info_get(pid);
292 if (NULL == kni_test) {
293 printf("Failed to get KNI info of the port %d\n",pid);
296 struct rte_kni_ops kni_ops_test = {
297 .change_mtu = kni_change_mtu,
298 .config_network_if = NULL,
300 /* test of registering kni with NULL ops */
301 if (rte_kni_register_handlers(kni_test,NULL) == 0) {
302 printf("unexpectedly register kni successfully"
306 if (rte_kni_register_handlers(kni_test,&kni_ops_test) < 0) {
307 printf("Failed to register KNI request handler"
308 "of the port %d\n",pid);
311 if (system(IFCONFIG " vEth0 mtu 1450") == -1)
314 rte_kni_handle_request(kni_test);
315 if (kni_pkt_mtu != TEST_MTU_SIZE) {
316 printf("Failed to change kni MTU\n");
320 /* test of unregistering kni request */
322 if (rte_kni_unregister_handlers(kni_test) < 0) {
323 printf("Failed to unregister kni request handlers\n");
326 if (system(IFCONFIG " vEth0 mtu 1450") == -1)
329 rte_kni_handle_request(kni_test);
330 if (kni_pkt_mtu != 0) {
331 printf("Failed to test kni unregister handlers\n");
335 }else if (p_id < 0) {
336 printf("Failed to fork a process\n");
339 p_ret = wait(&status);
340 if (WIFEXITED(status))
341 printf("test of multi-process api passed.\n");
343 printf("KNI test:The child process %d exit abnormally./n",p_ret);
347 rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
348 RTE_LCORE_FOREACH_SLAVE(i) {
349 if (rte_eal_wait_lcore(i) < 0) {
355 * Check if the number of mbufs received from kernel space is equal
356 * to that of transmitted to kernel space
358 if (stats.ingress < KNI_NUM_MBUF_THRESHOLD ||
359 stats.egress < KNI_NUM_MBUF_THRESHOLD) {
360 printf("The ingress/egress number should not be "
361 "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD);
366 /* test of creating kni on a port which has been used for a kni */
367 if (rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops) != NULL) {
368 printf("should not create a kni successfully for a port which"
369 "has been used for a kni\n");
374 if (rte_kni_release(kni) < 0) {
375 printf("fail to release kni\n");
380 /* test of releasing a released kni device */
381 if (rte_kni_release(kni) == 0) {
382 printf("should not release a released kni device\n");
386 /* test of reusing memzone */
387 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
389 printf("fail to create kni\n");
393 /* Release the kni for following testing */
394 if (rte_kni_release(kni) < 0) {
395 printf("fail to release kni\n");
401 if (rte_kni_release(kni) < 0) {
402 printf("fail to release kni\n");
413 uint8_t nb_ports, pid;
415 struct rte_mempool * mp;
417 if (test_kni_allocate_lcores() < 0) {
418 printf("No enough lcores for kni processing\n");
422 mp = test_kni_create_mempool();
424 printf("fail to create mempool for kni\n");
427 ret = rte_pmd_init_all();
429 printf("fail to initialize PMD\n");
432 ret = rte_eal_pci_probe();
434 printf("fail to probe PCI devices\n");
438 nb_ports = rte_eth_dev_count();
440 printf("no supported nic port found\n");
444 /* configuring port 0 for the test is enough */
446 ret = rte_eth_dev_configure(pid, 1, 1, &port_conf);
448 printf("fail to configure port %d\n", pid);
452 ret = rte_eth_rx_queue_setup(pid, 0, NB_RXD, SOCKET, &rx_conf, mp);
454 printf("fail to setup rx queue for port %d\n", pid);
458 ret = rte_eth_tx_queue_setup(pid, 0, NB_TXD, SOCKET, &tx_conf);
460 printf("fail to setup tx queue for port %d\n", pid);
464 ret = rte_eth_dev_start(pid);
466 printf("fail to start port %d\n", pid);
470 rte_eth_promiscuous_enable(pid);
472 /* basic test of kni processing */
473 ret = test_kni_processing(pid, mp);
477 /* test of creating kni with port id exceeds the maximum */
478 kni = rte_kni_create(RTE_MAX_ETHPORTS, MAX_PACKET_SZ, mp, &kni_ops);
480 printf("unexpectedly creates kni successfully with an invalid "
485 /* test of creating kni with NULL mempool pointer */
486 kni = rte_kni_create(pid, MAX_PACKET_SZ, NULL, &kni_ops);
488 printf("unexpectedly creates kni successfully with NULL "
489 "mempool pointer\n");
493 /* test of creating kni with NULL ops */
494 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, NULL);
496 printf("unexpectedly creates kni falied with NULL ops\n");
500 /* test of releasing kni with NULL ops */
501 if (rte_kni_release(kni) < 0) {
502 printf("fail to release kni\n");
506 /* test of getting port id according to NULL kni context */
507 if (rte_kni_get_port_id(NULL) < RTE_MAX_ETHPORTS) {
508 printf("unexpectedly get port id successfully by NULL kni "
513 /* test of releasing NULL kni context */
514 ret = rte_kni_release(NULL);
516 printf("unexpectedly release kni successfully\n");
523 rte_eth_dev_stop(pid);
528 #else /* RTE_LIBRTE_KNI */
533 printf("The KNI library is not included in this build\n");
537 #endif /* RTE_LIBRTE_KNI */