netmap源码分析(二)内核态关键结构的初始化

函数调用过程预览:

ixgbe_netmap_attach()
  |-- netmap_attach()
        |-- _netmap_attach()
              |-- netmap_attach_common()
                    |-- na->nm_krings_create()
                          |-- netmap_krings_create()
                    |-- na->nm_notify()

好,我们具体来看看各个函数

ixgbe_netmap_attach —— 初步初始化 na

static void ixgbe_netmap_attach(struct SOFTC_T *adapter)
{
    struct netmap_adapter na;
    bzero(&na, sizeof(na));

    na.ifp = adapter->netdev;  // ifp 是 net_device 结构
    na.pdev = &adapter->pdev->dev;
    na.num_tx_desc = NM_IXGBE_TX_RING(adapter, 0)->count;  // 根据ixgbe的发送队列槽个数来赋值
    na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;  // 根据ixgbe的接收队列槽个数来赋值
    na.nm_txsync = ixgbe_netmap_txsync;  // 内核态发送函数
    na.nm_rxsync = ixgbe_netmap_rxsync;  // 内核态收包函数
    na.nm_register = ixgbe_netmap_reg;
    na.num_tx_rings = adapter->num_tx_queues;  // 根据ixgbe的发送队列个数赋值
    na.num_rx_rings = adapter->num_rx_queues;  // 根据ixgbe的接收队列个数赋值
    na.nm_intr = ixgbe_netmap_intr;
    netmap_attach(&na);
}

注: SOFTC_T 是一个对应不同驱动的宏,对于 ixgbe,SOFTC_T 是 ixgbe_adapter。

上面函数主要是对netmap_adapter的一些成员赋值的过程。
下面我们来看看 netmap_adapter 的庐山真面目。

netmap_adapter 的庐山真面目

struct netmap_adapter {
    uint32_t na_flags;
    u_int num_rx_rings; /* RX 队列个数 */
    u_int num_tx_rings; /* TX 队列个数 */
    u_int num_tx_desc;  /* 发送队列槽个数 */
    u_int num_rx_desc;  /* 接收队列槽个数 */
    struct netmap_kring *tx_rings; /* TX 队列 */
    struct netmap_kring *rx_rings; /* RX 队列 */
    NM_SELINFO_T si[NR_TXRX];      /* 全局的等待队列 */
    struct ifnet *ifp;             /* net_device 结构 */

    /* 下面是一些比较主要的回调函数 */
    int (*nm_txsync)(struct netmap_kring *kring, int flags);
    int (*nm_rxsync)(struct netmap_kring *kring, int flags);
    int (*nm_notify)(struct netmap_kring *kring, int flags);

    int (*nm_config)(struct netmap_adapter *, u_int *txr, u_int *txd, u_int *rxr, u_int *rxd);
    int (*nm_krings_create)(struct netmap_adapter *);
    void (*nm_krings_delete)(struct netmap_adapter *);
};

下面是 attach 函数的主要部分:

static int _netmap_attach(struct netmap_adapter *arg, size_t size)
{
    struct netmap_hw_adapter *hwna = NULL;
    struct ifnet *ifp = NULL;

    ifp = arg->ifp;
    hwna = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
    hwna->up = *arg;  // up 指向了 na
    if (netmap_attach_common(&hwna->up)) {  // 对 na 的余下成员进行配置
        free(hwna, M_DEVBUF);
        goto fail;
    }
}

netmap_attach_common —— 进一步对 na 赋值

下面是对 na 的进一步赋值:

int netmap_attach_common(struct netmap_adapter *na)
{
    na->nm_krings_create = netmap_hw_krings_create;  // 实际调用 netmap_krings_create() 函数建立队列
    na->nm_krings_delete = netmap_hw_krings_delete;
    na->nm_notify = netmap_notify;  // 唤醒等待队列函数
}

netmap 一对好基友 —— TX/RX

看看 TX/RX 的建立过程:

// 对收发队列进行初始化
int netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
{
    struct netmap_kring *kring;
    u_int n[NR_TXRX];
    enum txrx t;

    n[NR_TX] = na->num_tx_rings + 1;  /* TX 队列 */
    n[NR_RX] = na->num_rx_rings + 1;  /* RX 队列 */

    // 总长度 TX + RX + tailroom  
    len = (n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring) + tailroom;

    na->tx_rings = malloc((size_t)len, M_DEVBUF, M_NOWAIT | M_ZERO);
    na->rx_rings = na->tx_rings + n[NR_TX];

    for_rx_tx(t) {
        for (i = 0; i < n[t]; i++) {  // 遍历所有的队列并初始化
            kring = &NMR(na, t)[i];
            bzero(kring, sizeof(*kring));
            kring->na = na;  /* 每个队列都指向 na */
            kring->ring_id = i;
            kring->tx = t;
            kring->nkr_num_slots = ndesc;
            kring->nm_sync = (t == NR_TX ? na->nm_txsync : na->nm_rxsync);
            kring->nm_notify = na->nm_notify; /* 队列的唤醒函数就是 na 的等待队列唤醒函数 */
            kring->rhead = kring->rcur = kring->nr_hwcur = 0; /* 指针偏移都在起始处 */
            mtx_init(&kring->q_lock, (t == NR_TX ? "nm_txq_lock" : "nm_rxq_lock"), NULL, MTX_DEF);
        }
    }

    na->tailroom = na->rx_rings + n[NR_RX];
    return 0;
}

TX/RX 布局图

tx_rings、rx_rings 和 tailroom 布局图如下:

                   +----------+
na->tx_rings ----->|          | \
                   |          |  } na->num_tx_ring
                   |          | /
                   +----------+
                   |          |    host tx kring
na->rx_rings ----> +----------+
                   |          | \
                   |          |  } na->num_rx_rings
                   |          | /
                   +----------+
                   |          |    host rx kring
                   +----------+
na->tailroom ----->|          | \
                   |          |  } tailroom bytes
                   |          | /
                   +----------+

当 netmap_notify 来敲门

下面就是唤醒函数了:
喂,有好吃的了,大家起来吃东西吧 ^_^

// 唤醒函数
static int netmap_notify(struct netmap_kring *kring, int flags)
{
    struct netmap_adapter *na = kring->na;
    enum txrx t = kring->tx;

    nm_os_selwakeup(&kring->si);  // 实际调用 wake_up_interruptible() 函数,唤醒等待队列上的进程
    if (na->si_users[t] > 0)
        nm_os_selwakeup(&na->si[t]);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值