⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xen-netfront.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		printk(KERN_WARNING "%s: add sysfs failed err=%d\n",		       __func__, err);		goto fail;	}	return 0; fail:	free_netdev(netdev);	dev->dev.driver_data = NULL;	return err;}static void xennet_end_access(int ref, void *page){	/* This frees the page as a side-effect */	if (ref != GRANT_INVALID_REF)		gnttab_end_foreign_access(ref, 0, (unsigned long)page);}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;}/** * We are reconnecting to the backend, due to a suspend/resume, or a backend * driver restart.  We tear down our netif structure and recreate it, but * leave the device-layer structures intact so that this is transparent to the * rest of the kernel. */static int netfront_resume(struct xenbus_device *dev){	struct netfront_info *info = dev->dev.driver_data;	dev_dbg(&dev->dev, "%s\n", dev->nodename);	xennet_disconnect_backend(info);	return 0;}static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]){	char *s, *e, *macstr;	int i;	macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);	if (IS_ERR(macstr))		return PTR_ERR(macstr);	for (i = 0; i < ETH_ALEN; i++) {		mac[i] = simple_strtoul(s, &e, 16);		if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {			kfree(macstr);			return -ENOENT;		}		s = e+1;	}	kfree(macstr);	return 0;}static irqreturn_t xennet_interrupt(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct netfront_info *np = netdev_priv(dev);	unsigned long flags;	spin_lock_irqsave(&np->tx_lock, flags);	if (likely(netif_carrier_ok(dev))) {		xennet_tx_buf_gc(dev);		/* Under tx_lock: protects access to rx shared-ring indexes. */		if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))			netif_rx_schedule(dev, &np->napi);	}	spin_unlock_irqrestore(&np->tx_lock, flags);	return IRQ_HANDLED;}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;	}	txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);	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);	err = xenbus_grant_ring(dev, virt_to_mfn(txs));	if (err < 0) {		free_page((unsigned long)txs);		goto fail;	}	info->tx_ring_ref = err;	rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);	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;	err = xenbus_alloc_evtchn(dev, &info->evtchn);	if (err)		goto fail;	err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,					IRQF_SAMPLE_RANDOM, netdev->name,					netdev);	if (err < 0)		goto fail;	netdev->irq = err;	return 0; fail:	return err;}/* Common code used when first setting up, and when resuming. */static int talk_to_backend(struct xenbus_device *dev,			   struct netfront_info *info){	const char *message;	struct xenbus_transaction xbt;	int err;	/* Create shared ring, alloc event channel. */	err = setup_netfront(dev, info);	if (err)		goto out;again:	err = xenbus_transaction_start(&xbt);	if (err) {		xenbus_dev_fatal(dev, err, "starting transaction");		goto destroy_ring;	}	err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",			    info->tx_ring_ref);	if (err) {		message = "writing tx ring-ref";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",			    info->rx_ring_ref);	if (err) {		message = "writing rx ring-ref";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename,			    "event-channel", "%u", info->evtchn);	if (err) {		message = "writing event-channel";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",			    1);	if (err) {		message = "writing request-rx-copy";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);	if (err) {		message = "writing feature-rx-notify";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);	if (err) {		message = "writing feature-sg";		goto abort_transaction;	}	err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);	if (err) {		message = "writing feature-gso-tcpv4";		goto abort_transaction;	}	err = xenbus_transaction_end(xbt, 0);	if (err) {		if (err == -EAGAIN)			goto again;		xenbus_dev_fatal(dev, err, "completing transaction");		goto destroy_ring;	}	return 0; abort_transaction:	xenbus_transaction_end(xbt, 1);	xenbus_dev_fatal(dev, err, "%s", message); destroy_ring:	xennet_disconnect_backend(info); out:	return err;}static int xennet_set_sg(struct net_device *dev, u32 data){	if (data) {		struct netfront_info *np = netdev_priv(dev);		int val;		if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",				 "%d", &val) < 0)			val = 0;		if (!val)			return -ENOSYS;	} else if (dev->mtu > ETH_DATA_LEN)		dev->mtu = ETH_DATA_LEN;	return ethtool_op_set_sg(dev, data);}static int xennet_set_tso(struct net_device *dev, u32 data){	if (data) {		struct netfront_info *np = netdev_priv(dev);		int val;		if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,				 "feature-gso-tcpv4", "%d", &val) < 0)			val = 0;		if (!val)			return -ENOSYS;	}	return ethtool_op_set_tso(dev, data);}static void xennet_set_features(struct net_device *dev){	/* Turn off all GSO bits except ROBUST. */	dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;	dev->features |= NETIF_F_GSO_ROBUST;	xennet_set_sg(dev, 0);	/* We need checksum offload to enable scatter/gather and TSO. */	if (!(dev->features & NETIF_F_IP_CSUM))		return;	if (!xennet_set_sg(dev, 1))		xennet_set_tso(dev, 1);}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);	/* 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;	/*	 * 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;}/** * Callback received when the backend's state changes. */static void backend_changed(struct xenbus_device *dev,			    enum xenbus_state backend_state){	struct netfront_info *np = dev->dev.driver_data;	struct net_device *netdev = np->netdev;	dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));	switch (backend_state) {	case XenbusStateInitialising:	case XenbusStateInitialised:	case XenbusStateConnected:	case XenbusStateUnknown:	case XenbusStateClosed:		break;	case XenbusStateInitWait:		if (dev->state != XenbusStateInitialising)			break;		if (xennet_connect(netdev) != 0)			break;		xenbus_switch_state(dev, XenbusStateConnected);		break;	case XenbusStateClosing:		xenbus_frontend_closed(dev);		break;	}}static struct ethtool_ops xennet_ethtool_ops ={	.set_tx_csum = ethtool_op_set_tx_csum,	.set_sg = xennet_set_sg,	.set_tso = xennet_set_tso,	.get_link = ethtool_op_get_link,};#ifdef CONFIG_SYSFSstatic ssize_t show_rxbuf_min(struct device *dev,			      struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	struct netfront_info *info = netdev_priv(netdev);	return sprintf(buf, "%u\n", info->rx_min_target);}static ssize_t store_rxbuf_min(struct device *dev,			       struct device_attribute *attr,			       const char *buf, size_t len){	struct net_device *netdev = to_net_dev(dev);	struct netfront_info *np = netdev_priv(netdev);	char *endp;	unsigned long target;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	target = simple_strtoul(buf, &endp, 0);	if (endp == buf)		return -EBADMSG;	if (target < RX_MIN_TARGET)		target = RX_MIN_TARGET;	if (target > RX_MAX_TARGET)		target = RX_MAX_TARGET;	spin_lock_bh(&np->rx_lock);	if (target > np->rx_max_target)		np->rx_max_target = target;	np->rx_min_target = target;	if (target > np->rx_target)		np->rx_target = target;	xennet_alloc_rx_buffers(netdev);	spin_unlock_bh(&np->rx_lock);	return len;}static ssize_t show_rxbuf_max(struct device *dev,			      struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	struct netfront_info *info = netdev_priv(netdev);	return sprintf(buf, "%u\n", info->rx_max_target);}static ssize_t store_rxbuf_max(struct device *dev,			       struct device_attribute *attr,			       const char *buf, size_t len){	struct net_device *netdev = to_net_dev(dev);	struct netfront_info *np = netdev_priv(netdev);	char *endp;	unsigned long target;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	target = simple_strtoul(buf, &endp, 0);	if (endp == buf)		return -EBADMSG;	if (target < RX_MIN_TARGET)		target = RX_MIN_TARGET;	if (target > RX_MAX_TARGET)		target = RX_MAX_TARGET;	spin_lock_bh(&np->rx_lock);	if (target < np->rx_min_target)		np->rx_min_target = target;	np->rx_max_target = target;	if (target < np->rx_target)		np->rx_target = target;	xennet_alloc_rx_buffers(netdev);	spin_unlock_bh(&np->rx_lock);	return len;}static ssize_t show_rxbuf_cur(struct device *dev,			      struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	struct netfront_info *info = netdev_priv(netdev);	return sprintf(buf, "%u\n", info->rx_target);}static struct device_attribute xennet_attrs[] = {	__ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),	__ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),	__ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),};static int xennet_sysfs_addif(struct net_device *netdev){	int i;	int err;	for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {		err = device_create_file(&netdev->dev,					   &xennet_attrs[i]);		if (err)			goto fail;	}	return 0; fail:	while (--i >= 0)		device_remove_file(&netdev->dev, &xennet_attrs[i]);	return err;}static void xennet_sysfs_delif(struct net_device *netdev){	int i;	for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)		device_remove_file(&netdev->dev, &xennet_attrs[i]);}#endif /* CONFIG_SYSFS */static struct xenbus_device_id netfront_ids[] = {	{ "vif" },	{ "" }};static int __devexit xennet_remove(struct xenbus_device *dev){	struct netfront_info *info = dev->dev.driver_data;	dev_dbg(&dev->dev, "%s\n", dev->nodename);	unregister_netdev(info->netdev);	xennet_disconnect_backend(info);	del_timer_sync(&info->rx_refill_timer);	xennet_sysfs_delif(info->netdev);	free_netdev(info->netdev);	return 0;}static struct xenbus_driver netfront = {	.name = "vif",	.owner = THIS_MODULE,	.ids = netfront_ids,	.probe = netfront_probe,	.remove = __devexit_p(xennet_remove),	.resume = netfront_resume,	.otherend_changed = backend_changed,};static int __init netif_init(void){	if (!is_running_on_xen())		return -ENODEV;	if (is_initial_xendomain())		return 0;	printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");	return xenbus_register_frontend(&netfront);}module_init(netif_init);static void __exit netif_exit(void){	if (is_initial_xendomain())		return;	return xenbus_unregister_driver(&netfront);}module_exit(netif_exit);MODULE_DESCRIPTION("Xen virtual network device frontend");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -