ia64/xen-unstable

annotate linux-2.6-xen-sparse/drivers/xen/netback/loopback.c @ 10298:d8363da485ce

[NET] loopback: Added support for SG

Just like the standard loopback device, SG support here is innate.
So all we need to do is mark it as such and zero the change_mtu method
so that the MTU can be changed at will.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
author kaf24@firebug.cl.cam.ac.uk
date Fri Jun 02 12:19:33 2006 +0100 (2006-06-02)
parents 48c0f5489d44
children bb46d03f5f1d
rev   line source
kaf24@4938 1 /******************************************************************************
kaf24@4938 2 * netback/loopback.c
kaf24@4938 3 *
kaf24@4938 4 * A two-interface loopback device to emulate a local netfront-netback
kaf24@4938 5 * connection. This ensures that local packet delivery looks identical
kaf24@4938 6 * to inter-domain delivery. Most importantly, packets delivered locally
kaf24@4938 7 * originating from other domains will get *copied* when they traverse this
kaf24@4938 8 * driver. This prevents unbounded delays in socket-buffer queues from
kaf24@4938 9 * causing the netback driver to "seize up".
kaf24@4938 10 *
kaf24@4938 11 * This driver creates a symmetric pair of loopback interfaces with names
kaf24@4938 12 * vif0.0 and veth0. The intention is that 'vif0.0' is bound to an Ethernet
kaf24@4938 13 * bridge, just like a proper netback interface, while a local IP interface
kaf24@4938 14 * is configured on 'veth0'.
kaf24@4938 15 *
kaf24@4938 16 * As with a real netback interface, vif0.0 is configured with a suitable
kaf24@4938 17 * dummy MAC address. No default is provided for veth0: a reasonable strategy
kaf24@4938 18 * is to transfer eth0's MAC address to veth0, and give eth0 a dummy address
kaf24@4938 19 * (to avoid confusing the Etherbridge).
kaf24@4938 20 *
kaf24@4938 21 * Copyright (c) 2005 K A Fraser
kaf24@9386 22 *
kaf24@9386 23 * This program is free software; you can redistribute it and/or
kaf24@9386 24 * modify it under the terms of the GNU General Public License version 2
kaf24@9386 25 * as published by the Free Software Foundation; or, when distributed
kaf24@9386 26 * separately from the Linux kernel or incorporated into other
kaf24@9386 27 * software packages, subject to the following license:
kaf24@9386 28 *
kaf24@9386 29 * Permission is hereby granted, free of charge, to any person obtaining a copy
kaf24@9386 30 * of this source file (the "Software"), to deal in the Software without
kaf24@9386 31 * restriction, including without limitation the rights to use, copy, modify,
kaf24@9386 32 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
kaf24@9386 33 * and to permit persons to whom the Software is furnished to do so, subject to
kaf24@9386 34 * the following conditions:
kaf24@9386 35 *
kaf24@9386 36 * The above copyright notice and this permission notice shall be included in
kaf24@9386 37 * all copies or substantial portions of the Software.
kaf24@9386 38 *
kaf24@9386 39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
kaf24@9386 40 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
kaf24@9386 41 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
kaf24@9386 42 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
kaf24@9386 43 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
kaf24@9386 44 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
kaf24@9386 45 * IN THE SOFTWARE.
kaf24@4938 46 */
kaf24@4938 47
kaf24@4938 48 #include <linux/config.h>
kaf24@4938 49 #include <linux/module.h>
kaf24@4938 50 #include <linux/netdevice.h>
kaf24@4938 51 #include <linux/inetdevice.h>
kaf24@4938 52 #include <linux/etherdevice.h>
kaf24@4938 53 #include <linux/skbuff.h>
kaf24@8632 54 #include <linux/ethtool.h>
kaf24@4938 55 #include <net/dst.h>
kaf24@4938 56
emellor@7706 57 static int nloopbacks = 8;
kaf24@6712 58 module_param(nloopbacks, int, 0);
kaf24@6712 59 MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
kaf24@6712 60
kaf24@4938 61 struct net_private {
kaf24@6712 62 struct net_device *loopback_dev;
kaf24@6712 63 struct net_device_stats stats;
kaf24@4938 64 };
kaf24@4938 65
kaf24@4938 66 static int loopback_open(struct net_device *dev)
kaf24@4938 67 {
kaf24@6712 68 struct net_private *np = netdev_priv(dev);
kaf24@6712 69 memset(&np->stats, 0, sizeof(np->stats));
kaf24@6712 70 netif_start_queue(dev);
kaf24@6712 71 return 0;
kaf24@4938 72 }
kaf24@4938 73
kaf24@4938 74 static int loopback_close(struct net_device *dev)
kaf24@4938 75 {
kaf24@6712 76 netif_stop_queue(dev);
kaf24@6712 77 return 0;
kaf24@4938 78 }
kaf24@4938 79
kaf24@4938 80 static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
kaf24@4938 81 {
kaf24@6712 82 struct net_private *np = netdev_priv(dev);
kaf24@4938 83
kaf24@6712 84 dst_release(skb->dst);
kaf24@6712 85 skb->dst = NULL;
kaf24@4938 86
kaf24@6712 87 skb_orphan(skb);
kaf24@4938 88
kaf24@6712 89 np->stats.tx_bytes += skb->len;
kaf24@6712 90 np->stats.tx_packets++;
kaf24@4938 91
kaf24@6712 92 /* Switch to loopback context. */
kaf24@6712 93 dev = np->loopback_dev;
kaf24@6712 94 np = netdev_priv(dev);
kaf24@4938 95
kaf24@6712 96 np->stats.rx_bytes += skb->len;
kaf24@6712 97 np->stats.rx_packets++;
kaf24@4938 98
kaf24@6712 99 if (skb->ip_summed == CHECKSUM_HW) {
kaf24@6712 100 /* Defer checksum calculation. */
kaf24@6712 101 skb->proto_csum_blank = 1;
kaf24@6712 102 /* Must be a local packet: assert its integrity. */
kaf24@9567 103 skb->proto_data_valid = 1;
kaf24@6712 104 }
kaf24@5095 105
kaf24@9567 106 skb->ip_summed = skb->proto_data_valid ?
kaf24@6712 107 CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
kaf24@5077 108
kaf24@6712 109 skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
kaf24@6712 110 skb->protocol = eth_type_trans(skb, dev);
kaf24@6712 111 skb->dev = dev;
kaf24@6712 112 dev->last_rx = jiffies;
kaf24@6712 113 netif_rx(skb);
kaf24@4938 114
kaf24@6712 115 return 0;
kaf24@4938 116 }
kaf24@4938 117
kaf24@4938 118 static struct net_device_stats *loopback_get_stats(struct net_device *dev)
kaf24@4938 119 {
kaf24@6712 120 struct net_private *np = netdev_priv(dev);
kaf24@6712 121 return &np->stats;
kaf24@4938 122 }
kaf24@4938 123
kaf24@9567 124 static struct ethtool_ops network_ethtool_ops =
kaf24@9567 125 {
kaf24@9567 126 .get_tx_csum = ethtool_op_get_tx_csum,
kaf24@9567 127 .set_tx_csum = ethtool_op_set_tx_csum,
kaf24@9567 128 };
kaf24@9567 129
kaf24@9918 130 /*
kaf24@9918 131 * Nothing to do here. Virtual interface is point-to-point and the
kaf24@9918 132 * physical interface is probably promiscuous anyway.
kaf24@9918 133 */
kaf24@9918 134 static void loopback_set_multicast_list(struct net_device *dev)
kaf24@9918 135 {
kaf24@9918 136 }
kaf24@9918 137
kaf24@4938 138 static void loopback_construct(struct net_device *dev, struct net_device *lo)
kaf24@4938 139 {
kaf24@6712 140 struct net_private *np = netdev_priv(dev);
kaf24@6712 141
kaf24@6712 142 np->loopback_dev = lo;
kaf24@4938 143
kaf24@6712 144 dev->open = loopback_open;
kaf24@6712 145 dev->stop = loopback_close;
kaf24@6712 146 dev->hard_start_xmit = loopback_start_xmit;
kaf24@6712 147 dev->get_stats = loopback_get_stats;
kaf24@9918 148 dev->set_multicast_list = loopback_set_multicast_list;
kaf24@10298 149 dev->change_mtu = NULL; /* allow arbitrary mtu */
kaf24@6712 150
kaf24@6712 151 dev->tx_queue_len = 0;
kaf24@6712 152
kaf24@9567 153 dev->features = (NETIF_F_HIGHDMA |
kaf24@9567 154 NETIF_F_LLTX |
kaf24@10298 155 NETIF_F_SG |
kaf24@9567 156 NETIF_F_IP_CSUM);
kaf24@9567 157
kaf24@9567 158 SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
kaf24@4938 159
kaf24@6712 160 /*
kaf24@6712 161 * We do not set a jumbo MTU on the interface. Otherwise the network
kaf24@6712 162 * stack will try to send large packets that will get dropped by the
kaf24@6712 163 * Ethernet bridge (unless the physical Ethernet interface is
kaf24@6712 164 * configured to transfer jumbo packets). If a larger MTU is desired
kaf24@6712 165 * then the system administrator can specify it using the 'ifconfig'
kaf24@6712 166 * command.
kaf24@6712 167 */
kaf24@6712 168 /*dev->mtu = 16*1024;*/
kaf24@6712 169 }
kaf24@4938 170
kaf24@6712 171 static int __init make_loopback(int i)
kaf24@6712 172 {
kaf24@6712 173 struct net_device *dev1, *dev2;
kaf24@6712 174 char dev_name[IFNAMSIZ];
kaf24@6712 175 int err = -ENOMEM;
kaf24@5006 176
kaf24@6712 177 sprintf(dev_name, "vif0.%d", i);
kaf24@6712 178 dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
vhanquez@8934 179 if (!dev1)
vhanquez@8934 180 return err;
vhanquez@8934 181
kaf24@6712 182 sprintf(dev_name, "veth%d", i);
kaf24@6712 183 dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
vhanquez@8934 184 if (!dev2)
vhanquez@8934 185 goto fail_netdev2;
kaf24@6712 186
kaf24@6712 187 loopback_construct(dev1, dev2);
kaf24@6712 188 loopback_construct(dev2, dev1);
kaf24@6712 189
kaf24@6712 190 /*
kaf24@6712 191 * Initialise a dummy MAC address for the 'dummy backend' interface. We
kaf24@6712 192 * choose the numerically largest non-broadcast address to prevent the
kaf24@6712 193 * address getting stolen by an Ethernet bridge for STP purposes.
kaf24@6712 194 */
kaf24@6712 195 memset(dev1->dev_addr, 0xFF, ETH_ALEN);
kaf24@6712 196 dev1->dev_addr[0] &= ~0x01;
kaf24@6712 197
kaf24@6712 198 if ((err = register_netdev(dev1)) != 0)
kaf24@6712 199 goto fail;
kaf24@6712 200
kaf24@6712 201 if ((err = register_netdev(dev2)) != 0) {
kaf24@6712 202 unregister_netdev(dev1);
kaf24@6712 203 goto fail;
kaf24@6712 204 }
kaf24@6712 205
kaf24@6712 206 return 0;
kaf24@6712 207
kaf24@6712 208 fail:
vhanquez@8934 209 free_netdev(dev2);
vhanquez@8934 210 fail_netdev2:
vhanquez@8934 211 free_netdev(dev1);
kaf24@6712 212 return err;
kaf24@4938 213 }
kaf24@4938 214
kaf24@9071 215 static void __init clean_loopback(int i)
kaf24@9071 216 {
kaf24@9071 217 struct net_device *dev1, *dev2;
kaf24@9071 218 char dev_name[IFNAMSIZ];
kaf24@9071 219
kaf24@9071 220 sprintf(dev_name, "vif0.%d", i);
kaf24@9071 221 dev1 = dev_get_by_name(dev_name);
kaf24@9071 222 sprintf(dev_name, "veth%d", i);
kaf24@9071 223 dev2 = dev_get_by_name(dev_name);
kaf24@9071 224 if (dev1 && dev2) {
kaf24@9071 225 unregister_netdev(dev2);
kaf24@9071 226 unregister_netdev(dev1);
kaf24@9071 227 free_netdev(dev2);
kaf24@9071 228 free_netdev(dev1);
kaf24@9071 229 }
kaf24@9071 230 }
kaf24@9071 231
kaf24@4938 232 static int __init loopback_init(void)
kaf24@4938 233 {
kaf24@6712 234 int i, err = 0;
kaf24@5077 235
kaf24@6712 236 for (i = 0; i < nloopbacks; i++)
kaf24@6712 237 if ((err = make_loopback(i)) != 0)
kaf24@6712 238 break;
kaf24@4938 239
kaf24@6712 240 return err;
kaf24@4938 241 }
kaf24@4938 242
kaf24@4938 243 module_init(loopback_init);
kaf24@6712 244
kaf24@9071 245 static void __exit loopback_exit(void)
kaf24@9071 246 {
kaf24@9071 247 int i;
kaf24@9071 248
kaf24@9071 249 for (i = nloopbacks; i-- > 0; )
kaf24@9071 250 clean_loopback(i);
kaf24@9071 251 }
kaf24@9071 252
kaf24@9071 253 module_exit(loopback_exit);
kaf24@9071 254
kaf24@9071 255 MODULE_LICENSE("Dual BSD/GPL");