高性能网络I/O框架-netmap源码分析(2)-阿里云开发者社区

开发者社区> xumaojun> 正文

高性能网络I/O框架-netmap源码分析(2)

简介: 作者:gfree.wind@gmail.com 博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net 微博:weibo.com/glinuxer QQ技术群:4367710 前面e1000_probe的分析,按照Linux驱动框架,接下来就该e1000_open。
+关注继续查看


作者:gfree.wind@gmail.com
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
微博:weibo.com/glinuxer
QQ技术群:4367710

前面e1000_probe的分析,按照Linux驱动框架,接下来就该e1000_open。netmap并没有对e1000_open进行任何修改,而是改动了e1000_configure,其会被e1000_open及e1000_up调用。

e1000_configure的修改

按照惯例,还是先看diff文件

@@ -393,6 +397,10 @@ static void e1000_configure(struct e1000
    e1000_configure_tx(adapter);
    e1000_setup_rctl(adapter);
    e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+   if (e1000_netmap_init_buffers(adapter))
+       return;
+#endif /* DEV_NETMAP */
    /* call E1000_DESC_UNUSED which always leaves
    * at least 1 descriptor unused to make sure
    * next_to_use != next_to_clean */ 

从diff文件可以看出,netmap替代了原有的e1000申请ring buffer的代码。如果e1000_netmap_init_buffers成功返回,e1000_configure就直接退出了。

接下来进入e1000_netmap_init_buffers:

/*
* Make the tx and rx rings point to the netmap buffers.
*/
static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
{
    struct e1000_hw *hw = &adapter->hw;
    struct ifnet *ifp = adapter->netdev;
    struct netmap_adapter* na = NA(ifp);
    struct netmap_slot* slot;
    struct e1000_tx_ring* txr = &adapter->tx_ring[0];
    unsigned int i, r, si;
    uint64_t paddr;

    /* 
    还记得前面的netmap_attach吗?
    所谓的attach,即申请了netmap_adapter,并将net_device->ax25_ptr保存了指针,并设置了NETMAP_SET_CAPABLE。
    因此这里做一个sanity check,以免影响正常的网卡驱动
    */
    if (!na || !(na->ifp->if_capenable & IFCAP_NETMAP))
        return 0;
    /* e1000_no_rx_alloc如其名,为一个不该调用的函数,只输出一行错误日志 */
    adapter->alloc_rx_buf = e1000_no_rx_alloc;
    for (r = 0; r num_rx_rings; r++) {
        struct e1000_rx_ring *rxr;
        /* 初始化对应的netmap对应的ring */
        slot = netmap_reset(na, NR_RX, r, 0);
        if (!slot) {
            D("strange, null netmap ring %d", r);
            return 0;
        }
        /* 得到e1000对应的ring */
        rxr = &adapter->rx_ring[r];

        for (i = 0; i count; i++) {
            // XXX the skb check and cleanup can go away
            struct e1000_buffer *bi = &rxr->buffer_info[i];
            /* 将当前的buff索引转换为netmap的buff索引 */
            si = netmap_idx_n2k(&na->rx_rings[r], i);
            /* 获得netmap的buff的物理地址 */
            PNMB(slot + si, &paddr);
            if (bi->skb)
                D("rx buf %d was set", i);
            bi->skb = NULL;
            // netmap_load_map(...)
            /* 现在网卡的这个buffer已经指向了netmap申请的buff地址了 */
            E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
        }

        rxr->next_to_use = 0;

        /* 
        下面这几行代码没看明白怎么回事。
        有明白的同学指点一下,多谢。
        */
        /* preserve buffers already made available to clients */
        i = rxr->count - 1 - na->rx_rings[0].nr_hwavail;
        if (i count;
        D("i now is %d", i);
        wmb(); /* Force memory writes to complete */
        writel(i, hw->hw_addr + rxr->rdt);
    }

    /* 
    初始化发送ring,与接收类似.
    区别在于没有考虑发送多队列。难道是因为e1000只可能是接收多队列,发送只可能是一个队列?
    这个问题不影响后面的代码阅读。咱们可以暂时将其假设为e1000只有一个发送队列
    */
    /* now initialize the tx ring(s) */
    slot = netmap_reset(na, NR_TX, 0, 0);
    for (i = 0; i num_tx_desc; i++) {
        si = netmap_idx_n2k(&na->tx_rings[0], i);
        PNMB(slot + si, &paddr);
        // netmap_load_map(...)
        E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
    }
    return 1;
} 

e1000cleanrx_irq的修改

@@ -3952,6 +3973,11 @@ static bool e1000_clean_rx_irq(struct e1
    bool cleaned = false;
    unsigned int total_rx_bytes=0, total_rx_packets=0;

+#ifdef DEV_NETMAP
+   ND("calling netmap_rx_irq");
+   if (netmap_rx_irq(netdev, 0, work_done))
+       return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
    i = rx_ring->next_to_clean;
    rx_desc = E1000_RX_DESC(*rx_ring, i);
    buffer_info = &rx_ring->buffer_info[i]; 

进入netmap_rx_irq, int netmaprxirq(struct ifnet *ifp, int q, int *workdone) { struct netmapadapter *na; struct netmap_kring *r; NMSELINFOT *main_wq;

 if (!(ifp->if_capenable & IFCAP_NETMAP))
        return 0;

    na = NA(ifp);

    /* 
    尽管函数名为rx,但实际上这个函数服务于rx和tx两种情况,用work_done做区分。
    */
    if (work_done) { /* RX path */
        r = na->rx_rings + q;
        r->nr_kflags |= NKR_PENDINTR;
        main_wq = (na->num_rx_rings > 1) ? &na->rx_si : NULL;
    } else { /* tx path */
        r = na->tx_rings + q;
        main_wq = (na->num_tx_rings > 1) ? &na->tx_si : NULL;
        work_done = &q; /* dummy */
    }


    /* 
    na->separate_locks只在ixgbe和bridge中会被设置为1。
    根据下面的代码,这个separate_locks表示多队列时,是每个队列使用一个锁。——这样可以提高性能
    其余的代码基本相同。都是唤醒等待数据的进程。
     */
    if (na->separate_locks) {
        mtx_lock(&r->q_lock);
        selwakeuppri(&r->si, PI_NET);
        mtx_unlock(&r->q_lock);
        if (main_wq) {
            mtx_lock(&na->core_lock);
            selwakeuppri(main_wq, PI_NET);
            mtx_unlock(&na->core_lock);
        }
    } else {
        mtx_lock(&na->core_lock);
        selwakeuppri(&r->si, PI_NET);
        if (main_wq)
            selwakeuppri(main_wq, PI_NET);
        mtx_unlock(&na->core_lock);
    }
    *work_done = 1; /* do not fire napi again */
    return 1;
} 


发送部分的修改与接收类似,就不重复了。
今天的学习,到此为止 (未完待续。。。)


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Linux USB Host-Controller的初始化代码框架分析【转】
转自:http://blog.csdn.net/zkami/article/details/2496770 usb_hcd_omap_probe (const struct hc_driver *driver) (dev/ohci/ohci-omap.
815 0
LinkedHashMap源码分析(基于JDK1.6)
LinkedHashMap类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点;而在迭代访问时反而更快,因为它使用链表维护内部次序(HashMap是基于散列表实现的,相关HashMap的内容可以看《Java集合类》和《HashMap源码分析》)。
586 0
TreeMap源码分析——基础分析(基于JDK1.6)
常见的数据结构有数组、链表,还有一种结构也很常见,那就是树。前面介绍的集合类有基于数组的ArrayList,有基于链表的LinkedList,还有链表和数组结合的HashMap,今天介绍基于树的TreeMap。
409 0
HashMap源码分析(基于JDK1.6)
在Java集合类中最常用的除了ArrayList外,就是HashMap了。本文尽自己所能,尽量详细的解释HashMap的源码。一山还有一山高,有不足之处请之处,定感谢指定并及时修正。     在看HashMap源码之前先复习一下数据结构。
497 0
Flink运行时之基于Netty的网络通信中
PartitionRequestClient 分区请求客户端(PartitionRequestClient)用于发起远程PartitionRequest请求,它也是RemoteChannel跟Netty通信层之间进行衔接的对象。
1850 0
基于对象存储 OSS 的智能数据分析处理框架和功能
今年参加了 2019 全球闪存峰会(Flash Memory World),分享了“基于云存储的智能数据分析处理架构”,重点介绍在对象存储 OSS 之上的数据处理功能,现整理相关内容和大家探讨。
2129 0
+关注
xumaojun
乐于学习与分析
1079
文章
95
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载