ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/loopback.c @ 10557:bb46d03f5f1d

[NET] loopback: Added support for TSO

Just like SG, TSO support here is innate. So all we need to do is mark it
as such. This patch also adds the ethtool control functions for SG.

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