高性能网络I/O框架-netmap源码分析(5)
作者:gfree.wind@gmail.com
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
微博:weibo.com/glinuxer
QQ技术群:4367710
今天继续前面的netmap_ioctl
netmap_ioctl
上次分析完了NIOCGINFO和NIOCREGIF两个,剩下的比较简单了。那么今天争取干掉剩下所有的case,以及上篇中netmap_ioctl调用的函数
NIOCUNREGIF
case NIOCUNREGIF: if (priv == NULL) { /* 没有priv肯定是不对的,肯定是没有调用过NIOCREGIF */ error = ENXIO; break; } /* the interface is unregistered inside the destructor of the private data. */ /* 释放priv内存*/ devfs_clear_cdevpriv(); break;
NIOCTXSYNC和NIOCRXSYNC
这两个使用相同的代码。
case NIOCTXSYNC: case NIOCRXSYNC: /* 检查priv,确保之前调用了NIOCREGIF */ if (priv == NULL) { error = ENXIO; break; } /* 记得之前分析NIOCREGIF时,priv->np_ifp保存了net_device指针,所有现在可以直接获得这个指针。 要不要担心net_device指针的有效性呢?不用,因为NIOCREGIF时,在得到net_device时,已经增加了计数 */ ifp = priv->np_ifp; /* we have a reference */ na = NA(ifp); /* retrieve netmap adapter */ /* np_qfirst表示需要检查的第一个ring 当其值为NETMAP_SW_RING是一个特殊的值,表示处理host的ring */ if (priv->np_qfirst == NETMAP_SW_RING) { /* host rings */ /* 对于host ring处理,这个地方的代码有点奇怪。 当cmd是NIOCTXSYNC,是将数据包传给host; 当cmd是NIOCRXSYNC,是将数据包从host发送出去; 感觉好像写反了。我给作者发了邮件,不知道能不能得到回复。 反正从语义上,我是觉得有问题。 现在已经得到了作者的回复——再次感叹外国人的友好。这里的方向,是以netmap的角度去看。 所以,当cmd是txsync时,是netmap把包送出去,那么自然是交给host。反之亦然。 */ if (cmd == NIOCTXSYNC) netmap_sync_to_host(na); else netmap_sync_from_host(na, NULL, NULL); break; } /* find the last ring to scan */ /* 得到需要检查的最后一个ring,如果是NETMAP_HW_RING,那么就是最大ring数值 关于np_qfirst和np_qlast,等看到netmap_set_ringid时,大家就明白了 */ lim = priv->np_qlast; if (lim == NETMAP_HW_RING) lim = (cmd == NIOCTXSYNC) ? na->num_tx_rings : na->num_rx_rings; /* 从第一个开始遍历每个ring */ for (i = priv->np_qfirst; i tx_rings[i]; if (netmap_verbose & NM_VERB_TXSYNC) D("pre txsync ring %d cur %d hwcur %d", i, kring->ring->cur, kring->nr_hwcur); /* 执行发送工作,留到后面分析 */ na->nm_txsync(ifp, i, 1 /* do lock */); if (netmap_verbose & NM_VERB_TXSYNC) D("post txsync ring %d cur %d hwcur %d", i, kring->ring->cur, kring->nr_hwcur); } else { /* 执行接收工作,留到后面分析*/ na->nm_rxsync(ifp, i, 1 /* do lock */); /* 在linux平台上,实际上是调用了do_gettimeofday,不知道为什么接收需要的这个时间 看看以后是不是可以知道原因。 */ microtime(&na->rx_rings[i].ring->ts); } }
到此,netmap_ioctl分析学习完毕。
netmap_set_ringid
在上篇文章中,遗留了这个函数。
static int netmap_set_ringid(struct netmap_priv_d *priv, u_int ringid) { struct ifnet *ifp = priv->np_ifp; struct netmap_adapter *na = NA(ifp); /* 从下面三个宏,可以得知ringid是一个“复用”的结构。低24位用于表示id值,高位作为标志。 #define NETMAP_HW_RING 0x4000 /* low bits indicate one hw ring */ #define NETMAP_SW_RING 0x2000 /* process the sw ring */ #define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */ #define NETMAP_RING_MASK 0xfff /* the ring number */ */ u_int i = ringid & NETMAP_RING_MASK; /* 根据注释,在初始化阶段,np_qfirst和np_qlast相等,不需要锁保护。 关于这点我没想明白。如果两个线程同时进入怎么办? */ /* initially (np_qfirst == np_qlast) we don't want to lock */ int need_lock = (priv->np_qfirst != priv->np_qlast); int lim = na->num_rx_rings; /* 上限取发送和接收队列数量的最大值 */ if (na->num_tx_rings > lim) lim = na->num_tx_rings; /* 当处理HW ring时,要对id进行有效性判断 */ if ( (ringid & NETMAP_HW_RING) && i >= lim) { D("invalid ring id %d", i); return (EINVAL); } if (need_lock) na->nm_lock(ifp, NETMAP_CORE_LOCK, 0); priv->np_ringid = ringid; /* 根据三种标志,设置正确的np_qfirst和qlast。从这里也可以看出,只有在初始化时,np_qfirst才可能等于np_qlast。 */ if (ringid & NETMAP_SW_RING) { priv->np_qfirst = NETMAP_SW_RING; priv->np_qlast = 0; } else if (ringid & NETMAP_HW_RING) { priv->np_qfirst = i; priv->np_qlast = i + 1; } else { priv->np_qfirst = 0; priv->np_qlast = NETMAP_HW_RING ; } /* 是否在执行接收数据包的poll时,发送数据包 */ priv->np_txpoll = (ringid & NETMAP_NO_TX_POLL) ? 0 : 1; if (need_lock) na->nm_lock(ifp, NETMAP_CORE_UNLOCK, 0); if (ringid & NETMAP_SW_RING) D("ringid %s set to SW RING", ifp->if_xname); else if (ringid & NETMAP_HW_RING) D("ringid %s set to HW RING %d", ifp->if_xname, priv->np_qfirst); else D("ringid %s set to all %d HW RINGS", ifp->if_xname, lim); return 0; }
(未完待续。。。)