DPDK KNI 接口2

参考文献:

  DPDK官网

........................................................................................................................................

一. DPDK KNI 作用

DPDK Kernel NIC Interface(KNI)允许用户空间应用程序访问Linux *控制面。

使用DPDK KNI的好处是:

  • 比现有的Linux TUN / TAP接口更快(通过消除系统调用和copy_to_user()/copy_from_user()操作)。
  • 允许使用标准Linux网络工具(如ethtool,ifconfig和tcpdump)管理DPDK端口。
  • 允许与内核网络堆栈的接口。

使用DPDK内核NIC接口的应用程序的组件如图所示。

Figure 21-1 Components of a DPDK KNI Application

 

KNI内核可加载模块支持两种类型的设备:

  • 其他设备:
    • 创建网络设备(通过ioctl调用)。
    • 维护所有KNI实例共享的内核线程上下文(模拟网络驱动程序的RX端)。
    • 对于单内核线程模式,维护所有KNI实例共享的内核线程上下文(模拟网络驱动程序的RX端)。
    • 对于多个内核线程模式,为每个KNI实例(模拟新驱动程序的RX侧)维护一个内核线程上下文。

网络设备:

  • 通过实现由struct net_device定义的诸如netdev_ops,header_ops,ethtool_ops之类的几个操作提供的Net功能,包括支持DPDK mbufs和FIFO。
  • 接口名称由用户空间提供。
  • MAC地址可以是真正的NIC MAC地址或随机

 

DPDK缓冲区流  

为了最小化在内核空间中运行的DPDK代码的数量,mbuf mempool仅在用户空间中进行管理。内核模块可以感知mbufs,但是所有mbuf分配和释放操作将仅由DPDK应用程序处理。

 

    • Figure 21-2 Packet Flow via mbufs in the DPDK KNI

kni 源码讲解

 1     /* Initialise EAL */
 2     ret = rte_eal_init(argc, argv);
 3     if (ret < 0)
 4         rte_exit(EXIT_FAILURE, "Could not initialise EAL (%d)
", ret);
 5     argc -= ret;
 6     argv += ret;
 7 
 8     /* Parse application arguments (after the EAL ones) */
 9     ret = parse_args(argc, argv);
10     if (ret < 0)
11         rte_exit(EXIT_FAILURE, "Could not parse input parameters
");
12 
13     /* Create the mbuf pool */
14     pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF,
15         MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, rte_socket_id());
16     if (pktmbuf_pool == NULL) {
17         rte_exit(EXIT_FAILURE, "Could not initialise mbuf pool
");
18         return -1;
19     }
20 
21     /* Get number of ports found in scan */
22     nb_sys_ports = rte_eth_dev_count_avail();
23     if (nb_sys_ports == 0)
24         rte_exit(EXIT_FAILURE, "No supported Ethernet device found
");
25 
26     /* Check if the configured port ID is valid */
27     for (i = 0; i < RTE_MAX_ETHPORTS; i++)
28         if (kni_port_params_array[i] && !rte_eth_dev_is_valid_port(i))
29             rte_exit(EXIT_FAILURE, "Configured invalid "
30                         "port ID %u
", i);
31 
32     /* Initialize KNI subsystem */
33     init_kni();
34 
35     /* Initialise each port */
36     RTE_ETH_FOREACH_DEV(port) {
37         /* Skip ports that are not enabled */
38         if (!(ports_mask & (1 << port)))
39             continue;
40         init_port(port);
41 
42         if (port >= RTE_MAX_ETHPORTS)
43             rte_exit(EXIT_FAILURE, "Can not use more than "
44                 "%d ports for kni
", RTE_MAX_ETHPORTS);
45 
46         kni_alloc(port);
47     }
48     check_all_ports_link_status(ports_mask);
49 
50     pid = getpid();
51     RTE_LOG(INFO, APP, "========================
");
52     RTE_LOG(INFO, APP, "KNI Running
");
53     RTE_LOG(INFO, APP, "kill -SIGUSR1 %d
", pid);
54     RTE_LOG(INFO, APP, "    Show KNI Statistics.
");
55     RTE_LOG(INFO, APP, "kill -SIGUSR2 %d
", pid);
56     RTE_LOG(INFO, APP, "    Zero KNI Statistics.
");
57     RTE_LOG(INFO, APP, "========================
");
58     fflush(stdout);
59 
60     ret = rte_ctrl_thread_create(&kni_link_tid,
61                      "KNI link status check", NULL,
62                      monitor_all_ports_link_status, NULL);
63     if (ret < 0)
64         rte_exit(EXIT_FAILURE,
65             "Could not create link status thread!
");
66 
67     /* Launch per-lcore function on every lcore */
68     rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
69     RTE_LCORE_FOREACH_SLAVE(i) {
70         if (rte_eal_wait_lcore(i) < 0)
71             return -1;
72     }
73     monitor_links = 0;
74     pthread_join(kni_link_tid, &retval);
75 
76     /* Release resources */
77     RTE_ETH_FOREACH_DEV(port) {
78         if (!(ports_mask & (1 << port)))
79             continue;
80         kni_free_kni(port);
81     }
82     for (i = 0; i < RTE_MAX_ETHPORTS; i++)
83         if (kni_port_params_array[i]) {
84             rte_free(kni_port_params_array[i]);
85             kni_port_params_array[i] = NULL;
86         }
87 
88     return 0;

main 主要完成步骤:

  1.进行EAL层的初始化

  2.解析DPDK和应用层的参数

  3.分配报文的mempool,为接收报文做准备

  4.初始化以及启动接口

  5.启动各个核上的线程

原文地址:https://www.cnblogs.com/mysky007/p/11219609.html