xen網絡前端驅動代碼分析(設備初始化篇)

無論是塊設備還是網絡設備,前端驅動模塊的安裝和卸載都通過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;
}



發佈了80 篇原創文章 · 獲贊 21 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章