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.
40 #include <cmdline_parse.h>
45 #include <rte_mempool.h>
46 #include <rte_ethdev.h>
47 #include <rte_cycles.h>
50 #define NB_MBUF (8192 * 16)
51 #define MAX_PACKET_SZ 2048
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
59 #define KNI_TIMEOUT_MS 5000 /* ms */
61 #define IFCONFIG "/sbin/ifconfig"
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;
67 struct test_kni_stats {
68 volatile uint64_t ingress;
69 volatile uint64_t egress;
72 static const struct rte_eth_rxconf rx_conf = {
81 static const struct rte_eth_txconf tx_conf = {
91 static const struct rte_eth_conf port_conf = {
100 .mq_mode = ETH_DCB_NONE,
104 static struct rte_kni_ops kni_ops = {
106 .config_network_if = NULL,
109 static unsigned lcore_master, lcore_ingress, lcore_egress;
110 static struct rte_kni *test_kni_ctx;
111 static struct test_kni_stats stats;
113 static volatile uint32_t test_kni_processing_flag;
115 static struct rte_mempool *
116 test_kni_create_mempool(void)
118 struct rte_mempool * mp;
120 mp = rte_mempool_lookup("kni_mempool");
122 mp = rte_mempool_create("kni_mempool",
126 sizeof(struct rte_pktmbuf_pool_private),
127 rte_pktmbuf_pool_init,
137 static struct rte_mempool *
138 test_kni_lookup_mempool(void)
140 return rte_mempool_lookup("kni_mempool");
142 /* Callback for request of changing MTU */
144 kni_change_mtu(uint8_t port_id, unsigned new_mtu)
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);
153 * This loop fully tests the basic functions of KNI. e.g. transmitting,
154 * receiving to, from kernel space, and kernel requests.
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.
164 * Note: To support this testing, the KNI kernel module needs to be insmodded
165 * in one of its loopback modes.
168 test_kni_loop(__rte_unused void *arg)
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];
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)
180 if (system(IFCONFIG " vEth0 mtu 1400") == -1)
182 if (system(IFCONFIG " vEth0 down") == -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();
193 if (test_kni_processing_flag)
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])
202 num = rte_kni_tx_burst(test_kni_ctx, pkts_burst,
204 stats.ingress += num;
205 rte_kni_handle_request(test_kni_ctx);
207 for (i = num; i < nb_rx; i++) {
208 rte_pktmbuf_free(pkts_burst[i]);
212 } else if (lcore_id == lcore_egress) {
214 if (test_kni_processing_flag)
216 num = rte_kni_rx_burst(test_kni_ctx, pkts_burst,
219 for (nb_tx = 0; nb_tx < num; nb_tx++)
220 rte_pktmbuf_free(pkts_burst[nb_tx]);
228 test_kni_allocate_lcores(void)
230 unsigned i, count = 0;
232 lcore_master = rte_get_master_lcore();
233 printf("master lcore: %u\n", lcore_master);
234 for (i = 0; i < RTE_MAX_LCORE; i++) {
237 if (rte_lcore_is_enabled(i) && i != lcore_master) {
245 printf("count: %u\n", count);
247 return (count == 2 ? 0 : -1);
251 test_kni_processing(uint8_t pid, struct rte_mempool *mp)
262 /* basic test of kni processing */
263 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
265 printf("fail to create kni\n");
268 if (rte_kni_get_port_id(kni) != pid) {
269 printf("fail to get port id\n");
275 test_kni_processing_flag = 0;
279 /* create a subprocess to test the APIs of supporting multi-process */
282 struct rte_kni *kni_test;
283 #define TEST_MTU_SIZE 1450
284 kni_test = rte_kni_info_get(RTE_MAX_ETHPORTS);
286 printf("unexpectedly gets kni successfully with an invalid "
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);
295 struct rte_kni_ops kni_ops_test = {
296 .change_mtu = kni_change_mtu,
297 .config_network_if = NULL,
299 /* test of registering kni with NULL ops */
300 if (rte_kni_register_handlers(kni_test,NULL) == 0) {
301 printf("unexpectedly register kni successfully"
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);
310 if (system(IFCONFIG " vEth0 mtu 1450") == -1)
313 rte_kni_handle_request(kni_test);
314 if (kni_pkt_mtu != TEST_MTU_SIZE) {
315 printf("Failed to change kni MTU\n");
319 /* test of unregistering kni request */
321 if (rte_kni_unregister_handlers(kni_test) < 0) {
322 printf("Failed to unregister kni request handlers\n");
325 if (system(IFCONFIG " vEth0 mtu 1450") == -1)
328 rte_kni_handle_request(kni_test);
329 if (kni_pkt_mtu != 0) {
330 printf("Failed to test kni unregister handlers\n");
334 }else if (p_id < 0) {
335 printf("Failed to fork a process\n");
338 p_ret = wait(&status);
339 if (WIFEXITED(status))
340 printf("test of multi-process api passed.\n");
342 printf("KNI test:The child process %d exit abnormally./n",p_ret);
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) {
354 * Check if the number of mbufs received from kernel space is equal
355 * to that of transmitted to kernel space
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);
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");
373 if (rte_kni_release(kni) < 0) {
374 printf("fail to release kni\n");
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");
385 /* test of reusing memzone */
386 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, &kni_ops);
388 printf("fail to create kni\n");
392 /* Release the kni for following testing */
393 if (rte_kni_release(kni) < 0) {
394 printf("fail to release kni\n");
400 if (rte_kni_release(kni) < 0) {
401 printf("fail to release kni\n");
412 uint8_t nb_ports, pid;
414 struct rte_mempool * mp;
416 if (test_kni_allocate_lcores() < 0) {
417 printf("No enough lcores for kni processing\n");
421 mp = test_kni_create_mempool();
423 printf("fail to create mempool for kni\n");
426 ret = rte_pmd_init_all();
428 printf("fail to initialize PMD\n");
431 ret = rte_eal_pci_probe();
433 printf("fail to probe PCI devices\n");
437 nb_ports = rte_eth_dev_count();
439 printf("no supported nic port found\n");
443 /* configuring port 0 for the test is enough */
445 ret = rte_eth_dev_configure(pid, 1, 1, &port_conf);
447 printf("fail to configure port %d\n", pid);
451 ret = rte_eth_rx_queue_setup(pid, 0, NB_RXD, SOCKET, &rx_conf, mp);
453 printf("fail to setup rx queue for port %d\n", pid);
457 ret = rte_eth_tx_queue_setup(pid, 0, NB_TXD, SOCKET, &tx_conf);
459 printf("fail to setup tx queue for port %d\n", pid);
463 ret = rte_eth_dev_start(pid);
465 printf("fail to start port %d\n", pid);
469 rte_eth_promiscuous_enable(pid);
471 /* basic test of kni processing */
472 ret = test_kni_processing(pid, mp);
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);
479 printf("unexpectedly creates kni successfully with an invalid "
484 /* test of creating kni with NULL mempool pointer */
485 kni = rte_kni_create(pid, MAX_PACKET_SZ, NULL, &kni_ops);
487 printf("unexpectedly creates kni successfully with NULL "
488 "mempool pointer\n");
492 /* test of creating kni with NULL ops */
493 kni = rte_kni_create(pid, MAX_PACKET_SZ, mp, NULL);
495 printf("unexpectedly creates kni falied with NULL ops\n");
499 /* test of releasing kni with NULL ops */
500 if (rte_kni_release(kni) < 0) {
501 printf("fail to release kni\n");
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 "
512 /* test of releasing NULL kni context */
513 ret = rte_kni_release(NULL);
515 printf("unexpectedly release kni successfully\n");
522 rte_eth_dev_stop(pid);
527 #else /* RTE_LIBRTE_KNI */
532 printf("The KNI library is not included in this build\n");
536 #endif /* RTE_LIBRTE_KNI */