当dpdk不想在用户态实现协议栈的还,可以采用KNI 调用内核实现的协议栈
kni分为用户态和内核态
其内核态的入口为lib/librte_eal/linuxapp/kni/kni_misc.c中
#可以看这是个标准的ko的实现,其入口函数是kni_init
module_init(kni_init);
static int __init
kni_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中的写法
int
main(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 int
main_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 void
kni_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;
}
}
}
kni
猜你喜欢
转载自blog.csdn.net/tiantao2012/article/details/80678603
今日推荐
周排行