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

来源:互联网 发布:河北干部网络学校app 编辑:程序博客网 时间:2024/05/16 17:00

函数调用过程预览:

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 kringna->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 0
原创粉丝点击