netmap源码分析(一)插入 netmap 代码到驱动程序

一、概述

netmap 的简单介绍可以看我之前的一篇博客 netmap 介绍

netmap 分成两个部分:内核态部分和用户态部分

使用方式:在网卡驱动中插入 netmap 相关代码,接管原来驱动程序的处理流程。
这里以 ixgbe 为例,插入 netmap 相关代码总共有6处,分别是在:

  • ixgbe_clean_tx_irq( )
  • ixgbe_clean_rx_irq( )
  • ixgbe_configure_tx_ring( )
  • ixgbe_configure_rx_ring( )
  • ixgbe_probe( )
  • ixgbe_remove( )

二、插入 netmap 代码模块

+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <ixgbe_netmap_linux.h>
+#endif

ixgbe_clean_tx_irq

@@ -826,6 +842,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
    unsigned int total_bytes = 0, total_packets = 0;
    u16 i, eop, count = 0;

+#ifdef DEV_NETMAP
+   /*
+    * In netmap mode, all the work is done in the context
+    * of the client thread. Interrupt handlers only wake up
+    * clients, which may be sleeping on individual rings
+    * or on a global resource for all rings.
+    */
+   if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)  // 实际调用的是 netmap_rx_irq()
+       return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
    i = tx_ring->next_to_clean;

ixgbe_clean_rx_irq

@@ -1308,6 +1334,17 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
    u16 cleaned_count = 0;
    bool pkt_is_rsc = false;

+#ifdef DEV_NETMAP
+   int nm_irq;
+   /*
+    * Same as the txeof routine: only wakeup clients on intr.
+    */
+   nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);  // TX/RX 中断处理程序
+   if (nm_irq != NM_IRQ_PASS) {
+       *work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
+       return;
+   }
+#endif /* DEV_NETMAP */
    i = rx_ring->next_to_clean;

ixgbe_configure_tx_ring

@@ -2730,6 +2767,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
    } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
    if (!wait_loop)
        e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+   ixgbe_netmap_configure_tx_ring(adapter, reg_idx);  // 配置 netmap 的 TX 队列
+#endif /* DEV_NETMAP */

ixgbe_configure_rx_ring

@@ -3094,6 +3134,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
    IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);

    ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+   if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))  // 配置 netmap 的 RX 队列 
+       return;
+#endif /* DEV_NETMAP */
    ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));

ixgbe_probe

@@ -7450,6 +7494,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,

    e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
    cards_found++;
+
+#ifdef DEV_NETMAP
+   ixgbe_netmap_attach(adapter);  // 调用 netmap_attach()
+#endif /* DEV_NETMAP */
+
    return 0;

ixgbe_remove

@@ -7490,6 +7539,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
    struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
    struct net_device *netdev = adapter->netdev;

+#ifdef DEV_NETMAP
+   netmap_detach(netdev);  // 退出 netmap 模式
+#endif /* DEV_NETMAP */
+
    set_bit(__IXGBE_DOWN, &adapter->state);

三、大致流程

netmap 接手 NIC 的传输和接收 ring, 并将 ring 映射到用户态。
对于 RX ring 来说,内核态存放报文数据,用户态来收取。

 softc
+----------------+
| standard fields|
| if_pspare[0] --|-------+
+----------------+       |
                         |
+----------------+<------+
|(netmap_adapter)|
|                |                             netmap_kring
| tx_rings *-----|--------------------------->+---------------+
|                |       netmap_kring         | ring    *-----|---.
| rx_rings *-----|--->+---------------+       | nr_hwcur      |   |
+----------------+    | ring    *-----|--.    | nr_hwavail    |   V
                      | nr_hwcur      |  |    | selinfo       |   |
                      | nr_hwavail    |  |    +---------------+   .
                      | selinfo       |  |    |     ...       |   .
                      +---------------+  |    |(ntx+1 entries)|
                      |    ....       |  |    |               |
                      |(nrx+1 entries)|  |    +---------------+
                      |               |  |
   KERNEL             +---------------+  |
                                         |
  ====================================================================
                                         |
   USERSPACE                             |      struct netmap_ring
                                         +---->+---------------+
                                             / | head,cur,tail |
   struct netmap_if (nifp, one per fd)      /  | buf_ofs       |
    +---------------+                      /   | other fields  |
    | ni_tx_rings   |                     /    +===============+
    | ni_rx_rings   |                    /     | buf_idx, len  | slot[0]
    |               |                   /      | flags, ptr    |
    |               |                  /       +---------------+
    +===============+                 /        | buf_idx, len  | slot[1]
    | txring_ofs[0] | (rel.to nifp)--'         | flags, ptr    |
    | txring_ofs[1] |                          +---------------+
     (tx+1 entries)                           (num_slots entries)
    | txring_ofs[t] |                          | buf_idx, len  | slot[n-1]
    +---------------+                          | flags, ptr    |
    | rxring_ofs[0] |                          +---------------+
    | rxring_ofs[1] |
     (rx+1 entries)
    | rxring_ofs[r] |
    +---------------+

上图中有几个重要的结构,从内核态和用户态分别说明:

内核态:

  • netmap_adapter
    扩展了原来的 ixgbe_adapter 结构,netmap 有自己的报文收发同步和中断处理函数。

  • netmap_kring
    netmap 的队列,对应于网卡的队列,不过计算时需要加上偏移。

用户态:

  • netmap_if
    一个接口对应一个 netmap_if,也就是 eth0 有自己的 netmap_if,eth1 也有自己的 netmap_if。

  • netmap_ring
    每个队列对应一个 netmap_ring,它就是真正的收发队列,里面有读/写指针,还有用来缓冲报文的槽。

  • netmap_slot
    一个队列有很多槽,槽里面有用于存放报文的buffer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值