DPDK KNI 接口3

本文介绍了DPDK KNI(Kernel Network Interface)接口的工作原理,特别是内核模块rte_kni的加载参数,如回环模式(lo_mode)和链路状态。KNI通过/dev/kni设备节点与用户态交互,支持回环测试模式以模拟真实场景。同时,文章讨论了KNI的默认链路状态控制,以及如何通过rte_kni_update_link函数设置接口状态。KNI的报文处理涉及用户态和内核态的零拷贝机制,包括rx_q和tx_q队列的管理。
摘要由CSDN通过智能技术生成

图1. kni结构图

从结构图中可以看到KNI需要内核模块的支持,即rte_kni.ko

当rte_kni模块加载时,创建/dev/kni设备节点(rte_kni模块创建kni杂项设备,文件系统节点/dev/kni需要手动或者通过udev机制创建),藉此节点,DPDK KNI应用可控制和与内核rte_kni模块交互。

在内核模块rte_kni加载时,可指定一些可选的参数以控制其行为:

# modinfo rte_kni.ko
lo_mode:        KNI loopback mode (default=lo_mode_none):
                lo_mode_none        Kernel loopback disabled
                lo_mode_fifo        Enable kernel loopback with fifo
                lo_mode_fifo_skb    Enable kernel loopback with fifo and skb buffer
 
kthread_mode:   Kernel thread mode (default=single):
                single    Single kernel thread mode enabled.
                multiple  Multiple kernel thread mode enabled.
 
carrier:        Default carrier state for KNI interface (default=off):
                off   Interfaces will be created with carrier state set to off.                on Interfaces will be created with carrier state set to on.

典型的情况是,在加载rte_kni模块时不指定任何参数,DPDK应用可由内核网络协议栈获取和向其发送报文。不指定任何参数,意味着仅创建一个内核线程处理所有的KNI虚拟设备在内核侧的报文接收,并且禁用回环模式,KNI接口的默认链路状态为关闭off

回环模式

以测试为目的,在加载rte_kni模块式可指定lo_mode参数:

# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo lo_mode_fifo回环模式将在内核空间中操作FIFO环队列,由函数kni_fifo_get(kni->rx_q,...)和kni_fifo_put(kni->tx_q,...)实现从rx_q接收队列读取报文,再写入发送队列tx_q来实现回环操作。

# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo_skb

lo_mode_fifo_skb回环模式在以上lo_mode_fifo的基础之上,增加了sk_buff缓存的相关拷贝操作。具体包括将rx_q接收队列的数据拷贝到分配的接收skb缓存中。以及分配发送skb缓存,将之前由rx_q队列接收数据拷贝到发送skb缓存中,使用函数kni_net_tx(skb, dev)发送skb缓存数据。最终将数据报文拷贝到mbuf结构中,使用kni_fifo_put函数加入到tx_q发送队列。可见此回环测试模式,更加接近真实的使用场景

如果没有指定lo_mode参数,回环模式将禁用。

默认链路状态

内核模块rte_kni创建的KNI虚拟接口的链路状态,可通过模块加装时的carrier选项控制。

如果指定了carrier=off,当接口管理使能时,内核模块将接口的链路状态设置为关闭。DPDK应用可通过函数rte_kni_update_link设置KNI虚拟接口的链路状态。这对于需要KNI虚拟接口状态与对应的物理接口实际状态一致的应用是有用的。

如果指定了carrier=on,当接口管理使能时,内核模块将自动设置接口的链路状态为启用。这对于仅将KNI接口作为纯虚拟接口,而不对应任何物理硬件;或者并不想通过rte_kni_update_link函数显示设置接口链路状态的DPDK应用是有用的。对于物理口为连接任何链路而进行的回环模式测试也是有用的。

以下,设置默认的链路状态为启用:

# insmod kmod/rte_kni.ko carrier=on

以下,设置默认的链路状态为关闭:

# insmod kmod/rte_kni.ko carrier=off

如果carrier参数没有指定,KNI虚拟接口的默认链路状态为关闭。

在任何KNI虚拟接口创建之前,rte_kni内核模块必须加装到内核,并且经由rte_kni_init函数配置(获取/dev/kni设备节点文件句柄)

int rte_kni_init(unsigned int max_kni_ifaces __rte_unused)
{
    /* Check FD and open */
    if (kni_fd < 0) {
        kni_fd = open("/dev/" KNI_DEVICE, O_RDWR);
        if (kni_fd < 0) {
            RTE_LOG(ERR, KNI,
                "Can not open /dev/%s\n", KNI_DEVICE);
            return -1;
        }
}

模块初始化函数kni_init也非常简单。除了解析上面的参数配置外,比较重要的就是注册misc设备和配置lo_mode。

 1 static int __init
 2 kni_init(void)
 3 {
 4     int rc;
 5 
 6     if (kni_parse_kthread_mode() < 0) {
 7         pr_err("Invalid parameter for kthread_mode\n");
 8         return -EINVAL;
 9     }
10 
11     if (multiple_kthread_on == 0)
12         pr_debug("Single kernel thread for all KNI devices\n");
13     else
14         pr_debug("Multiple kernel thread mode enabled\n");
15 
16     if (kni_parse_carrier_state() < 0) {   //carrier可配置为off和on,默认为off
17         pr_err("Invalid parameter for carrier\n");
18         return -EINVAL;
19     }
20 
21     if (kni_dflt_carrier == 0)
22         pr_debug("Default carrier state set to off.\n");
23     else
24         pr_debug("Default carrier state set to on.\n");
25 
26 #ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS
27     rc = register_pernet_subsys(&kni_net_ops);
28 #else
29     rc = register_pernet_gen_subsys(&kni_net_id, &kni_net_ops);
30 #endif
31     if (rc)
32         return -EPERM;
33 
34     rc = misc_register(&kni_misc);
35     if (rc != 0) {
36         pr_err("Misc registration failed\n");
37         goto out;
38     }
39 
40     /* Configure the lo mode according to the input parameter */
41     kni_net_config_lo_mode(lo_mode);
42 
43     return 0;
44 
45 out:
46 #ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS
47     unregister_pernet_subsys(&kni_net_ops);
48 #else
49     unregister_pernet_gen_subsys(kni_net_id, &kni_net_ops);
50 #endif
51     return rc;
52 }

kni_net_config_lo_mode:

 1 void
 2 kni_net_config_lo_mode(char *lo_str)
 3 {
 4     if (!lo_str) {
 5         pr_debug("loopback disabled");
 6         return;
 7     }
 8 
 9     if (!strcmp(lo_str, "lo_mode_none"))
10         pr_debug("loopback disabled");
11     else if (!strcmp(lo_str, "lo_mode_fifo")) {
12         pr_debug("loopback mode=lo_mode_fifo enabled");
13         kni_net_rx_func = kni_net_rx_lo_fifo;
14     } else if (!strcmp(lo_str, "lo_mode_fifo_skb")) {
15         pr_debug("loopback mode=lo_mode_fifo_skb enabled");
16         kni_net_rx_func = kni_net_rx_lo_fifo_skb;
17     } else {
18         pr_debug("Unknown loopback parameter, disabled");
19     }
20 }

lo_mode可配置为lo_mode_none,lo_mode_fifo,和lo_mode_fifo_skb,默认为lo_mode_none。另外两个在实际产品中基本不会用到

配置lo_mode,函数指针kni_net_r

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值