无论是块设备还是网络设备,前端驱动模块的安装和卸载都通过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;
}