本文共 5053 字,大约阅读时间需要 16 分钟。
当dpdk不想在用户态实现协议栈的还,可以采用KNI 调用内核实现的协议栈kni分为用户态和内核态其内核态的入口为lib/librte_eal/linuxapp/kni/kni_misc.c中#可以看这是个标准的ko的实现,其入口函数是kni_initmodule_init(kni_init);static int __initkni_init(void){ int rc; #检查kthread_mode 这个参数是否等于single 或者 multiple if (kni_parse_kthread_mode() < 0) { pr_err("Invalid parameter for kthread_mode\n"); return -EINVAL; } if (multiple_kthread_on == 0) pr_debug("Single kernel thread for all KNI devices\n"); else pr_debug("Multiple kernel thread mode enabled\n"); #注册一个网络子系统#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS rc = register_pernet_subsys(&kni_net_ops);#else rc = register_pernet_gen_subsys(&kni_net_id, &kni_net_ops);#endif if (rc) return -EPERM; #注册一个misc设备,这个misc 设备包含ioctl操作 rc = misc_register(&kni_misc); if (rc != 0) { pr_err("Misc registration failed\n"); goto out; } #根据输入参数配置lo mode kni_net_config_lo_mode(lo_mode); return 0;}这个模块可以接受的参数如下:MODULE_PARM_DESC(lo_mode,"KNI loopback mode (default=lo_mode_none):\n"" lo_mode_none Kernel loopback disabled\n"" lo_mode_fifo Enable kernel loopback with fifo\n"" lo_mode_fifo_skb Enable kernel loopback with fifo and skb buffer\n""\n");module_param(kthread_mode, charp, S_IRUGO);MODULE_PARM_DESC(kthread_mode,"Kernel thread mode (default=single):\n"" single Single kernel thread mode enabled.\n"" multiple Multiple kernel thread mode enabled.\n""\n");可见可以配置lo mode和kthread_mode用户态可以参考example/kni/main.c中的写法intmain(int argc, char** argv){ int ret; uint16_t nb_sys_ports, port; unsigned i; /* Associate signal_hanlder function with USR signals */ #注册下面四个信号量的处理函数为signal_handler signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); signal(SIGRTMIN, signal_handler); signal(SIGINT, signal_handler); /* Initialise EAL */ #初始化eal环境。 ret = rte_eal_init(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Could not initialise EAL (%d)\n", ret); argc -= ret; argv += ret; /* Parse application arguments (after the EAL ones) */ ret = parse_args(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Could not parse input parameters\n"); /* Create the mbuf pool */ #创建pktmbuf_pool pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, rte_socket_id()); if (pktmbuf_pool == NULL) { rte_exit(EXIT_FAILURE, "Could not initialise mbuf pool\n"); return -1; } /* Get number of ports found in scan */ #得到网卡的port的个数 nb_sys_ports = rte_eth_dev_count(); if (nb_sys_ports == 0) rte_exit(EXIT_FAILURE, "No supported Ethernet device found\n"); /* Check if the configured port ID is valid */ #检查这些网口id 是否有效 for (i = 0; i < RTE_MAX_ETHPORTS; i++) if (kni_port_params_array[i] && i >= nb_sys_ports) rte_exit(EXIT_FAILURE, "Configured invalid " "port ID %u\n", i); /* Initialize KNI subsystem */ #初始化KNI 子系统 init_kni(); #让每个核都运行main_loop /* Launch per-lcore function on every lcore */ rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); RTE_LCORE_FOREACH_SLAVE(i) { if (rte_eal_wait_lcore(i) < 0) return -1; }}具体的mail_loop实现如下:static intmain_loop(__rte_unused void *arg){ uint8_t i, nb_ports = rte_eth_dev_count(); int32_t f_stop; const unsigned lcore_id = rte_lcore_id(); enum lcore_rxtx { LCORE_NONE, LCORE_RX, LCORE_TX, LCORE_MAX }; enum lcore_rxtx flag = LCORE_NONE; #具体是发送还是接受 for (i = 0; i < nb_ports; i++) { if (!kni_port_params_array[i]) continue; if (kni_port_params_array[i]->lcore_rx == (uint8_t)lcore_id) { flag = LCORE_RX; break; } else if (kni_port_params_array[i]->lcore_tx == (uint8_t)lcore_id) { flag = LCORE_TX; break; } } #给你讲flag决定是发送数据还是接受手机 if (flag == LCORE_RX) { RTE_LOG(INFO, APP, "Lcore %u is reading from port %d\n", kni_port_params_array[i]->lcore_rx, kni_port_params_array[i]->port_id); while (1) { f_stop = rte_atomic32_read(&kni_stop); if (f_stop) break; #循环接受数据 kni_ingress(kni_port_params_array[i]); } } else if (flag == LCORE_TX) { RTE_LOG(INFO, APP, "Lcore %u is writing to port %d\n", kni_port_params_array[i]->lcore_tx, kni_port_params_array[i]->port_id); while (1) { f_stop = rte_atomic32_read(&kni_stop); if (f_stop) break; #循环发送数据 kni_egress(kni_port_params_array[i]); } } else RTE_LOG(INFO, APP, "Lcore %u has nothing to do\n", lcore_id); return 0;}我们看看接受数据的情况static voidkni_ingress(struct kni_port_params *p){ uint8_t i; uint16_t port_id; unsigned nb_rx, num; uint32_t nb_kni; struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; if (p == NULL) return; nb_kni = p->nb_kni; port_id = p->port_id; for (i = 0; i < nb_kni; i++) { /* Burst rx from eth */ #首先从网口读数据到pkts_burst nb_rx = rte_eth_rx_burst(port_id, 0, pkts_burst, PKT_BURST_SZ); if (unlikely(nb_rx > PKT_BURST_SZ)) { RTE_LOG(ERR, APP, "Error receiving from eth\n"); return; } /* Burst tx to kni */ #将pkts_burst中的数据督导kni中 num = rte_kni_tx_burst(p->kni[i], pkts_burst, nb_rx); kni_stats[port_id].rx_packets += num; rte_kni_handle_request(p->kni[i]); if (unlikely(num < nb_rx)) { /* Free mbufs not tx to kni interface */ kni_burst_free_mbufs(&pkts_burst[num], nb_rx - num); kni_stats[port_id].rx_dropped += nb_rx - num; } }}
转载地址:http://hnnmi.baihongyu.com/