zoukankan      html  css  js  c++  java
  • [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 ", lcore_id);

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

    [root@dpdk ~]# 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
    [root@dpdk ~]# 

    数据结构:

    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 '01', port = 0 '00', 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指令,测量程序的运行速度 [转]  

  • 相关阅读:
    SpringBoot非官方教程 | 第九篇: springboot整合Redis
    SpringBoot非官方教程 | 第八篇:springboot整合mongodb
    SpringBoot非官方教程 | 第七篇:springboot开启声明式事务
    SpringBoot非官方教程 | 第六篇:springboot整合mybatis
    SpringBoot非官方教程 | 第五篇:springboot整合 beatlsql
    SpringBoot非官方教程 | 第四篇:SpringBoot 整合JPA
    SpringBoot非官方教程 | 第三篇:SpringBoot用JdbcTemplates访问Mysql
    SpringBoot非官方教程 | 第二篇:Spring Boot配置文件详解
    SpringBoot非官方教程 | 终章:文章汇总
    SpringBoot非官方教程 | 第一篇:构建第一个SpringBoot工程
  • 原文地址:https://www.cnblogs.com/hugetong/p/6085704.html
Copyright © 2011-2022 走看看