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
- netmap源码分析(二)内核态关键结构的初始化
- Netmap分析(二)
- netmap源码分析(三)内核态收包过程
- netmap源码分析(一)插入 netmap 代码到驱动程序
- xv6源码分析(二):内核初始化和多核启动
- Netmap分析(一)
- Netmap分析(三)
- Netmap分析(四)
- Netmap分析(五)
- Netmap分析(六)
- netmap源码分析(四)用户态收包过程
- netmap源码分析(五)ioctl 注册过程
- trafficserver的DNS初始化源码分析二
- Android Wi-Fi源码分析之wpa_supplicant初始化(二):wpa_supplicant_init中的三个关键点
- WebKit内核源码分析(二)---dlmu2001
- struts2源码分析(二)(初始化)
- Linux内核源码分析--系统时间初始化(kernel_mktime()函数)
- Tachyon源码结构分析(二)
- android四种定位方式
- 【第九周项目4-广义表算法库及应用】
- Java数据结构-TreeMap
- 第10周项目3-利用二叉树遍历思想解决问题(1)计算二叉树节点个数
- 第八周项目3 顺序串算法
- netmap源码分析(二)内核态关键结构的初始化
- Spring实战-注解切面(五)
- 第八周 项目一 建立顺序串的算法库
- centos7 install samba
- mongodb,memcached与redis在win7下的使用
- sensor总结三(sensor校准)
- 计算表、视图、序列、存储过程的个数
- 第十周项目2-二叉树遍历的递归算法
- stack,deque,queue对比