[dpdk] 熟悉SDK与初步使用 (二)(skeleton源码分析)

接续前节:[dpdk] 熟悉SDK与初步使用 (一)(qemu搭建实验环境)

程序逻辑:

运行参数:

关键API:

入口函数:

  int rte_eal_init(int argc, char **argv)

内存池函数:

  rte_pktmbuf_pool_create。  它是函数 rte_mempool_create 的一个封装。

struct rte_mempool *
rte_pktmbuf_pool_create(const char *name, unsigned n,
        unsigned cache_size, uint16_t priv_size, uint16_t data_room_size,
        int socket_id)

name是内存池名字。为了获得更好的性能,n应该为2的幂减1 。

网卡操作函数:

  rte_eth_dev_configure() 设置网卡设备。在其他操作之前,应该先调用这个函数进行设置。

  rte_eth_rx_queue_setup()  申请并设置一个收包队列。

    关键参数:

      struct rte_mempool *mp; 由前文创建的pool

  rte_eth_tx_queue_setup()  同上。

  rte_eth_dev_start() 就是设置好了之后就启动啊,该收的收,该发的发。

  rte_eth_promiscuous_enable()  启动混杂模式,不解释。

收发包函数:

  rte_eth_rx_burst()  收一大批包

    该接口不提供任何错误检测功能,上层应用可以在返回包数为零时,去主动检测link状态来完成接口异常及错误检测机制。

    关键参数:

      struct rte_mbuf** rx_pkts;  一个指针数组,数组中的每一个指针指向收取到的一个包,具体的包结构查看下文的数据结构章节。指针所指向的内存空间为queue_setup(mpool) 函数中的参数pool提供。

      const uint16_t nb_pkts;  简单来说,就是数组大小。

    返回值:

      收到的报数,数组中被填充的item个数。

      当返回值== nb_pkts时,隐含说明,收包性能已经跟不上了。

      当返回值== 0 时,应该启动异常检测,查看接口状态等。

  rte_eth_tx_burst()  发一大批包

  rte_pktmbuf_free()  收到了但是没有被发出去的包,应该将其free,即还给mpool。咦,不过为什么会有没发出去的呢?奇怪

其他函数:

rte_eth_dev_count():

  返回可以被dpdk使用的网口个数。即(加载了UIO驱动,或VFIO ??) rte_eal_init 之后就可以用了。

rte_socket_id():

  返回CPU sock 的ID,即命令参数中指定的lcore所属的CPU socket。

回过头来,对比一下Helloworld。在helloworld里多使用了一个函数

rte_eal_remote_launch()   用于在多个核上启动多线程,原例子中用法如下:

        /* call lcore_hello() on every slave lcore */
        RTE_LCORE_FOREACH_SLAVE(lcore_id) {
                rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
        }        /* call it on master lcore too */ //      lcore_hello(NULL);
                 lcore_id = rte_lcore_id();
        printf("hello from master core %u\n", lcore_id);

主线程,跑着编号最小的那个核上,不知道是否可修改。

[[email protected] ~]# ps -eLF |grep -E "UID|helloworld"
UID        PID  PPID   LWP  C NLWP    SZ   RSS PSR STIME TTY          TIME CMD
root      2671  2531  2671 99    5 274512 3668   4 18:44 pts/0    00:05:22 ./helloworld -l4,5,6,7
root      2671  2531  2672  0    5 274512 3668   4 18:44 pts/0    00:00:00 ./helloworld -l4,5,6,7
root      2671  2531  2673  0    5 274512 3668   5 18:44 pts/0    00:00:00 ./helloworld -l4,5,6,7
root      2671  2531  2674  0    5 274512 3668   6 18:44 pts/0    00:00:00 ./helloworld -l4,5,6,7
root      2671  2531  2675  0    5 274512 3668   7 18:44 pts/0    00:00:00 ./helloworld -l4,5,6,7
root      2778  2679  2778  0    1 28162   964   0 18:50 pts/1    00:00:00 grep --color=auto -E UID|helloworld
[[email protected] ~]# 

数据结构:

struct rte_mbuf {}

gdb之: 去掉 -O3

设断点:

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000435829 in lcore_main at /root/src/sdk/@dpdk/dpdk-stable-16.07.1/examples/skeleton/basicfwd.c:143
        breakpoint already hit 1 time
(gdb) l 143
138             for (;;) {
139                     /*
140                      * Receive packets on a port and forward them on the paired
141                      * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
142                      */
143                     for (port = 0; port < nb_ports; port++) {
144
145                             /* Get burst of RX packets, from first port of pair. */
146                             struct rte_mbuf *bufs[BURST_SIZE];
147                             const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
(gdb) 

debug一个包:

包格式如下:

进入断点,看数据结构,如下:

(gdb) p bufs[0]
$20 = (struct rte_mbuf *) 0x7fffd9791b00
(gdb) p *bufs[0]
$21 = {cacheline0 = 0x7fffd9791b00, buf_addr = 0x7fffd9791b80, buf_physaddr = 972626816, buf_len = 2176, rearm_data = 0x7fffd9791b12 "\200", data_off = 128, {
    refcnt_atomic = {cnt = 1}, refcnt = 1}, nb_segs = 1 ‘\001‘, port = 0 ‘\000‘, ol_flags = 0, rx_descriptor_fields1 = 0x7fffd9791b20, {packet_type = 0, {
      l2_type = 0, l3_type = 0, l4_type = 0, tun_type = 0, inner_l2_type = 0, inner_l3_type = 0, inner_l4_type = 0}}, pkt_len = 42, data_len = 42, vlan_tci = 0,
  hash = {rss = 0, fdir = {{{hash = 0, id = 0}, lo = 0}, hi = 0}, sched = {lo = 0, hi = 0}, usr = 0}, seqn = 0, vlan_tci_outer = 0, cacheline1 = 0x7fffd9791b40, {
    userdata = 0x0, udata64 = 0}, pool = 0x7fffd64436c0, next = 0x0, {tx_offload = 0, {l2_len = 0, l3_len = 0, l4_len = 0, tso_segsz = 0, outer_l3_len = 0,
      outer_l2_len = 0}}, priv_size = 0, timesync = 0}
(gdb) x/42xb (bufs[0].buf_addr + 128)
0x7fffd9791c00: 0xff    0xff    0xff    0xff    0xff    0xff    0x00    0x00
0x7fffd9791c08: 0x00    0x01    0x00    0x01    0x08    0x06    0x00    0x01
0x7fffd9791c10: 0x08    0x00    0x06    0x04    0x00    0x01    0x00    0x00
0x7fffd9791c18: 0x00    0x01    0x00    0x01    0x01    0x01    0x01    0x01
0x7fffd9791c20: 0x00    0x00    0x00    0x00    0x00    0x00    0x01    0x01
0x7fffd9791c28: 0x01    0x02
(gdb) where

回调函数和CPU cycle

  例子 rxtx_callback 在 skeleton 的基础之上增加了两个回调函数,在回调函数中做了cpu cycles的计算。

  rte_eth_add_rx_callback()

  rte_eth_add_tx_callback()

  关于CPU cycles可以参见另一篇博 [daily]使用rdtsc指令,测量程序的运行速度 [转]  

时间: 2024-10-22 03:59:12

[dpdk] 熟悉SDK与初步使用 (二)(skeleton源码分析)的相关文章

Spring IoC 依赖注入(二)源码分析

目录 Spring IoC 依赖注入(二)源码分析 1. 依赖注入口 - populateBean 1.1 doCreateBean 1.2 populateBean 2. 手动注入 2.1 相关的类说明 2.2 applyPropertyValues 2.3 BeanDefinitionValueResolver 2.4 依赖检查 2. 自动注入 2.1 那些字段会自动注入 2.2 名称注入 2.3 类型注入 Spring IoC 依赖注入(二)源码分析 本章主要分析 Spring IoC 依

Spring 循环引用(二)源码分析

Spring 循环引用(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) Spring 循环引用相关文章: <Spring 循环引用(一)一个循环依赖引发的 BUG>:https://www.cnblogs.com/binarylei/p/10325698.html <Spring 循环引用(二)源码分析>:https://www.cnblogs.com/binarylei/p/1032604

[dpdk] 熟悉SDK与初步使用 (三)(IP Fragmentation源码分析)

对例子IP Fragmentation的熟悉,使用,以及源码分析. 问题一: main()函数大概是这样的:标红的三行将与下面叙述的事情相关 int main(int argc, char **argv) { ... ... /* init EAL */ ret = rte_eal_init(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eal_init failed"); ... ... /* launch per-

Spark SQL之External DataSource外部数据源(二)源码分析

上周Spark1.2刚发布,周末在家没事,把这个特性给了解一下,顺便分析下源码,看一看这个特性是如何设计及实现的. /** Spark SQL源码分析系列文章*/ (Ps: External DataSource使用篇地址:Spark SQL之External DataSource外部数据源(一)示例 http://blog.csdn.net/oopsoom/article/details/42061077) 一.Sources包核心 Spark SQL在Spark1.2中提供了External

Spring IoC Bean 实例化(二)源码分析

目录 Spring IoC 依赖注入(四)构造器或工厂注入 1. doCreateBean 2. createBeanInstance 2. 实例化策略 - InstantiationStrategy 3. instantiateBean 4. autowireConstructor 4.1 整体说明 4.2 缓存匹配 4.3 无参构造器匹配 4.4 有参构造器匹配 5. ConstructorResolver 参数解析 5.1 resolveConstructorArguments 5.2 c

[dpdk] 熟悉SDK与初步使用 (一)(qemu搭建实验环境)

搭建实验环境: troubleshoot 第一步加载驱动 第二步切换驱动 使用了所有qemu支持的卡 [[email protected]:~/VM/dpdk] % cat start.sh sudo qemu-system-x86_64 -nographic -vnc 127.0.0.1:1 -enable-kvm -m 2G -cpu Nehalem -smp cores=2,threads=2,sockets=2 -numa node,mem=1G,cpus=0-3,nodeid=0 -n

Junit学习笔记(二): 源码分析(1)

使用ModelGoon画出来的UML图如下: 图中可以分析出: 1)Test是一个接口,TestSuit和TestCase,JUnit4TestAdapter,JUnit4TestCaseFacade都实现了Test类,这一种命令模式,只需要使用Test接口就可以使用到具体的类: 2)JUnit4TestAdapter是适配器, Filterable实现了对用例的过滤, Sortable实现了对用例的排序(按照字母进行排序): 3)TestResult实现了返回结果,TestFailure记录失

Junit学习笔记(二): 源码分析(2)-命令和组合模式

命令模式 命令模式的优点: 命令模式将调用操作的对象与如何实现该操作的对象解耦. 将命令当成一个头等对象,它们可以像一般对象那样进行操纵和扩展 可以将多个命令复合成一个命令,与Composite模式结合使用 增加新的命令很容易,隔离对现有类的影响 可以与备忘录模式配合,实现撤销功能. 命令模式图: 由此带来的好处:1.客户无需使用任何条件语句去判断测试的类型,可以用统一的方式调用测试和测试套件,解除了客户与具体测试子类的耦合2.如果要增加新的TestCase也很容易,实现Test接口即可,不会影

android线程(二)AsyncTask源码分析(二)

转载请注明出处:http://blog.csdn.net/itachi85/article/details/45055365 请看这篇文章之前看一下本作的前篇http://blog.csdn.net/itachi85/article/details/45041923 3.AsyncTask中的线程池  AsyncTask中一共定义了两个线程池一个是此前我们已经介绍了线程池SerialExecutor,这个是目前我们调用AsyncTask.execute()方法默认使用的线程池,这个在前一篇文章