xen网络前端驱动代码分析(设备初始化篇)

来源:互联网 发布:网贷大数据花了怎么办 编辑:程序博客网 时间:2024/04/29 12:22

无论是块设备还是网络设备,前端驱动模块的安装和卸载都通过xenbus_register_frontend,xenbus_unregister_driver来完成。 其中netfront_driver也是一个xenbus_driver结构

static struct xenbus_driver netfront_driver = {
    .name = "vif",
    .owner = THIS_MODULE,
    .ids = netfront_ids,
    .probe = netfront_probe,
    .remove = __devexit_p(xennet_remove),
    .resume = netfront_resume,
    .otherend_changed = backend_changed,
};


前端通过xennet_connect与后端简历连接,xennet_connect首先调用talk_to_backend,设置对应backend的参数,e.g.

tx-ring-ref

rx-ring-ref

event-channel

request-rx-copy

feature-rx-notify

feature-sg

feature-gso-tcpv4

其中request-rx-copy, feature-rx-notify, feature-sg, feature-gso-tcpv4都为1

注意调用xenbus_transaction_start()设置之前,还需要通过setup_netfront生成一个struct netfront_info结构体


static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
{
    struct xen_netif_tx_sring *txs;
    struct xen_netif_rx_sring *rxs;
    int err;
    struct net_device *netdev = info->netdev;

    info->tx_ring_ref = GRANT_INVALID_REF;
    info->rx_ring_ref = GRANT_INVALID_REF;
    info->rx.sring = NULL;
    info->tx.sring = NULL;
    netdev->irq = 0;

    err = xen_net_read_mac(dev, netdev->dev_addr);
    if (err) {
        xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
        goto fail;
    }

通过读取xenstore得到netfront mac地址

    txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
    if (!txs) {
        err = -ENOMEM;
        xenbus_dev_fatal(dev, err, "allocating tx ring page");
        goto fail;
    }
    SHARED_RING_INIT(txs);
    FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);

初始化tx IO ring page

    err = xenbus_grant_ring(dev, virt_to_mfn(txs));
    if (err < 0) {
        free_page((unsigned long)txs);
        goto fail;
    }

给后端grant这个tx IO ring page的access权限

    info->tx_ring_ref = err;
    rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
    if (!rxs) {
        err = -ENOMEM;
        xenbus_dev_fatal(dev, err, "allocating rx ring page");
        goto fail;
    }
    SHARED_RING_INIT(rxs);
    FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);

    err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
    if (err < 0) {
        free_page((unsigned long)rxs);
        goto fail;
    }
    info->rx_ring_ref = err;

同样的初始化rx IO ring page,并给后端grant access priviledge

    err = xenbus_alloc_evtchn(dev, &info->evtchn);
    if (err)
        goto fail;

初始化一个前后端的event channel

    err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
                    IRQF_SAMPLE_RANDOM, netdev->name,
                    netdev);

event channel的硬中断对应的IRQ服务例程为xennet_interrupt,该函数唤醒napi poll

    if (err < 0)
        goto fail;
    netdev->irq = err;
    return 0;

 fail:
    return err;
}


xennet_connect之后做一系列rx, tx的初始化工作,代码如下

static int xennet_connect(struct net_device *dev)
{
    struct netfront_info *np = netdev_priv(dev);
    int i, requeue_idx, err;
    struct sk_buff *skb;
    grant_ref_t ref;
    struct xen_netif_rx_request *req;
    unsigned int feature_rx_copy;

    err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
               "feature-rx-copy", "%u", &feature_rx_copy);
    if (err != 1)
        feature_rx_copy = 0;

    if (!feature_rx_copy) {
        dev_info(&dev->dev,
             "backend does not support copying receive path\n");
        return -ENODEV;
    }

    err = talk_to_backend(np->xbdev, np);
    if (err)
        return err;

    xennet_set_features(dev);

    spin_lock_bh(&np->rx_lock);
    spin_lock_irq(&np->tx_lock);

    /* Step 1: Discard all pending TX packet fragments. */
    xennet_release_tx_bufs(np);

释放tx_skbs的所有相应资源

    /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
    for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
        if (!np->rx_skbs[i])
            continue;

        skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
        ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
        req = RING_GET_REQUEST(&np->rx, requeue_idx);

        gnttab_grant_foreign_access_ref(
            ref, np->xbdev->otherend_id,
            pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
                           frags->page)),
            0);
        req->gref = ref;
        req->id   = requeue_idx;

        requeue_idx++;
    }

    np->rx.req_prod_pvt = requeue_idx;

把rx_skbs, grant_rx_ref数组的资源赋给xen_netif_rx_request的结构体,grant后端设备access权限,这样后端如果有包到达就可以把数据拷贝到相应page中


    /*
     * Step 3: All public and private state should now be sane.  Get
     * ready to start sending and receiving packets and give the driver
     * domain a kick because we've probably just requeued some
     * packets.
     */
    netif_carrier_on(np->netdev);
    notify_remote_via_irq(np->netdev->irq);
    xennet_tx_buf_gc(dev);
    xennet_alloc_rx_buffers(dev);

    spin_unlock_irq(&np->tx_lock);
    spin_unlock_bh(&np->rx_lock);

    return 0;
}


相应的xennet_disconnect_backend用来做相反的事情,释放event channel,释放tx, rx IO ring资源

static void xennet_disconnect_backend(struct netfront_info *info)
{
    /* Stop old i/f to prevent errors whilst we rebuild the state. */
    spin_lock_bh(&info->rx_lock);
    spin_lock_irq(&info->tx_lock);
    netif_carrier_off(info->netdev);
    spin_unlock_irq(&info->tx_lock);
    spin_unlock_bh(&info->rx_lock);

    if (info->netdev->irq)
        unbind_from_irqhandler(info->netdev->irq, info->netdev);
    info->evtchn = info->netdev->irq = 0;

    /* End access and free the pages */
    xennet_end_access(info->tx_ring_ref, info->tx.sring);
    xennet_end_access(info->rx_ring_ref, info->rx.sring);

    info->tx_ring_ref = GRANT_INVALID_REF;
    info->rx_ring_ref = GRANT_INVALID_REF;
    info->tx.sring = NULL;
    info->rx.sring = NULL;
}


netfront_probe,用来从xen pci bus中探测网卡设备。netfront_probe首先会调用xennet_create_dev通过xenbus_device设备创建net_device设备

static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
{
    int i, err;
    struct net_device *netdev;
    struct netfront_info *np;

    netdev = alloc_etherdev(sizeof(struct netfront_info));

alloc_etherdev创建只有一个rx queue, tx queue的net_device,其中net_device->priv为netfront_info指针


    if (!netdev) {
        printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
               __func__);
        return ERR_PTR(-ENOMEM);
    }

    np                   = netdev_priv(netdev);
    np->xbdev            = dev;

netfront_info->xbdev为xenbus_device设备指针


    spin_lock_init(&np->tx_lock);
    spin_lock_init(&np->rx_lock);

    skb_queue_head_init(&np->rx_batch);
    np->rx_target     = RX_DFL_MIN_TARGET;
    np->rx_min_target = RX_DFL_MIN_TARGET;
    np->rx_max_target = RX_MAX_TARGET;

    init_timer(&np->rx_refill_timer);
    np->rx_refill_timer.data = (unsigned long)netdev;
    np->rx_refill_timer.function = rx_refill_timeout;

    /* Initialise tx_skbs as a free chain containing every entry. */
    np->tx_skb_freelist = 0;
    for (i = 0; i < NET_TX_RING_SIZE; i++) {
        skb_entry_set_link(&np->tx_skbs[i], i+1);
        np->grant_tx_ref[i] = GRANT_INVALID_REF;
    }

    /* Clear out rx_skbs */
    for (i = 0; i < NET_RX_RING_SIZE; i++) {
        np->rx_skbs[i] = NULL;
        np->grant_rx_ref[i] = GRANT_INVALID_REF;
    }

    /* A grant for every tx ring slot */
    if (gnttab_alloc_grant_references(TX_MAX_TARGET,
                      &np->gref_tx_head) < 0) {
        printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
        err = -ENOMEM;
        goto exit;
    }
    /* A grant for every rx ring slot */
    if (gnttab_alloc_grant_references(RX_MAX_TARGET,
                      &np->gref_rx_head) < 0) {
        printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
        err = -ENOMEM;
        goto exit_free_tx;
    }

    netdev->netdev_ops  = &xennet_netdev_ops;

    netif_napi_add(netdev, &np->napi, xennet_poll, 64);
    netdev->features        = NETIF_F_IP_CSUM;

    SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
    SET_NETDEV_DEV(netdev, &dev->dev);

    np->netdev = netdev;

    netif_carrier_off(netdev);

上面都是常规的net_device初始化步骤

    return netdev;

 exit_free_tx:
    gnttab_free_grant_references(np->gref_tx_head);
 exit:
    free_netdev(netdev);
    return ERR_PTR(err);
}


netfront_probe核心是调用register_netdev注册自己

static int __devinit netfront_probe(struct xenbus_device *dev,
                    const struct xenbus_device_id *id)
{
    int err;
    struct net_device *netdev;
    struct net_device *netdev_found=NULL;
    struct netfront_info *info;
    char mac_addr[ETH_ALEN];


    netdev = xennet_create_dev(dev);

    if (IS_ERR(netdev)) {
        err = PTR_ERR(netdev);
        xenbus_dev_fatal(dev, err, "creating netdev");
        return err;
    }

    info = netdev_priv(netdev);
    dev_set_drvdata(&dev->dev, info);

    err = register_netdev(info->netdev);
    if (err) {
        printk(KERN_WARNING "%s: register_netdev err=%d\n",
               __func__, err);
        goto fail;
    }

    err = xennet_sysfs_addif(info->netdev);
    if (err) {
        unregister_netdev(info->netdev);
        printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
               __func__, err);
        goto fail;
    }

    return 0;

fail:
    free_netdev(netdev);
    dev_set_drvdata(&dev->dev, NULL);
out:
    return err;
}



原创粉丝点击