高性能网络I/O框架-netmap源码分析(5)

高性能网络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;
} 

(未完待续。。。)

上一篇:【自然框架】终于把源码弄到git上了。


下一篇:Python面向对象编程01:入门类和对象