|
1 /* |
|
2 * INET An implementation of the TCP/IP protocol suite for the LINUX |
|
3 * operating system. INET is implemented using the BSD Socket |
|
4 * interface as the means of communication with the user level. |
|
5 * |
|
6 * Pseudo-driver for the loopback interface. |
|
7 * |
|
8 * Version: @(#)loopback.c 1.0.4b 08/16/93 |
|
9 * |
|
10 * Authors: Ross Biro |
|
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> |
|
12 * Donald Becker, <becker@scyld.com> |
|
13 * |
|
14 * Alan Cox : Fixed oddments for NET3.014 |
|
15 * Alan Cox : Rejig for NET3.029 snap #3 |
|
16 * Alan Cox : Fixed NET3.029 bugs and sped up |
|
17 * Larry McVoy : Tiny tweak to double performance |
|
18 * Alan Cox : Backed out LMV's tweak - the linux mm |
|
19 * can't take it... |
|
20 * Michael Griffith: Don't bother computing the checksums |
|
21 * on packets received on the loopback |
|
22 * interface. |
|
23 * Alexey Kuznetsov: Potential hang under some extreme |
|
24 * cases removed. |
|
25 * |
|
26 * This program is free software; you can redistribute it and/or |
|
27 * modify it under the terms of the GNU General Public License |
|
28 * as published by the Free Software Foundation; either version |
|
29 * 2 of the License, or (at your option) any later version. |
|
30 */ |
|
31 #include <linux/kernel.h> |
|
32 #include <linux/jiffies.h> |
|
33 #include <linux/module.h> |
|
34 #include <linux/interrupt.h> |
|
35 #include <linux/fs.h> |
|
36 #include <linux/types.h> |
|
37 #include <linux/string.h> |
|
38 #include <linux/socket.h> |
|
39 #include <linux/errno.h> |
|
40 #include <linux/fcntl.h> |
|
41 #include <linux/in.h> |
|
42 #include <linux/init.h> |
|
43 |
|
44 #include <asm/system.h> |
|
45 #include <asm/uaccess.h> |
|
46 #include <asm/io.h> |
|
47 |
|
48 #include <linux/inet.h> |
|
49 #include <linux/netdevice.h> |
|
50 #include <linux/etherdevice.h> |
|
51 #include <linux/skbuff.h> |
|
52 #include <linux/ethtool.h> |
|
53 #include <net/sock.h> |
|
54 #include <net/checksum.h> |
|
55 #include <linux/if_ether.h> /* For the statistics structure. */ |
|
56 #include <linux/if_arp.h> /* For ARPHRD_ETHER */ |
|
57 #include <linux/ip.h> |
|
58 #include <linux/tcp.h> |
|
59 #include <linux/percpu.h> |
|
60 #include <net/net_namespace.h> |
|
61 |
|
62 struct pcpu_lstats { |
|
63 unsigned long packets; |
|
64 unsigned long bytes; |
|
65 }; |
|
66 |
|
67 /* |
|
68 * The higher levels take care of making this non-reentrant (it's |
|
69 * called with bh's disabled). |
|
70 */ |
|
71 static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) |
|
72 { |
|
73 struct pcpu_lstats *pcpu_lstats, *lb_stats; |
|
74 |
|
75 skb_orphan(skb); |
|
76 |
|
77 skb->protocol = eth_type_trans(skb,dev); |
|
78 |
|
79 dev->last_rx = jiffies; |
|
80 |
|
81 /* it's OK to use per_cpu_ptr() because BHs are off */ |
|
82 pcpu_lstats = dev->ml_priv; |
|
83 lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); |
|
84 lb_stats->bytes += skb->len; |
|
85 lb_stats->packets++; |
|
86 |
|
87 netif_rx(skb); |
|
88 |
|
89 return 0; |
|
90 } |
|
91 |
|
92 static struct net_device_stats *get_stats(struct net_device *dev) |
|
93 { |
|
94 const struct pcpu_lstats *pcpu_lstats; |
|
95 struct net_device_stats *stats = &dev->stats; |
|
96 unsigned long bytes = 0; |
|
97 unsigned long packets = 0; |
|
98 int i; |
|
99 |
|
100 pcpu_lstats = dev->ml_priv; |
|
101 for_each_possible_cpu(i) { |
|
102 const struct pcpu_lstats *lb_stats; |
|
103 |
|
104 lb_stats = per_cpu_ptr(pcpu_lstats, i); |
|
105 bytes += lb_stats->bytes; |
|
106 packets += lb_stats->packets; |
|
107 } |
|
108 stats->rx_packets = packets; |
|
109 stats->tx_packets = packets; |
|
110 stats->rx_bytes = bytes; |
|
111 stats->tx_bytes = bytes; |
|
112 return stats; |
|
113 } |
|
114 |
|
115 static u32 always_on(struct net_device *dev) |
|
116 { |
|
117 return 1; |
|
118 } |
|
119 |
|
120 static const struct ethtool_ops loopback_ethtool_ops = { |
|
121 .get_link = always_on, |
|
122 .set_tso = ethtool_op_set_tso, |
|
123 .get_tx_csum = always_on, |
|
124 .get_sg = always_on, |
|
125 .get_rx_csum = always_on, |
|
126 }; |
|
127 |
|
128 static int loopback_dev_init(struct net_device *dev) |
|
129 { |
|
130 struct pcpu_lstats *lstats; |
|
131 |
|
132 lstats = alloc_percpu(struct pcpu_lstats); |
|
133 if (!lstats) |
|
134 return -ENOMEM; |
|
135 |
|
136 dev->ml_priv = lstats; |
|
137 return 0; |
|
138 } |
|
139 |
|
140 static void loopback_dev_free(struct net_device *dev) |
|
141 { |
|
142 struct pcpu_lstats *lstats = dev->ml_priv; |
|
143 |
|
144 free_percpu(lstats); |
|
145 free_netdev(dev); |
|
146 } |
|
147 |
|
148 /* |
|
149 * The loopback device is special. There is only one instance |
|
150 * per network namespace. |
|
151 */ |
|
152 static void loopback_setup(struct net_device *dev) |
|
153 { |
|
154 dev->get_stats = &get_stats; |
|
155 dev->mtu = (16 * 1024) + 20 + 20 + 12; |
|
156 dev->hard_start_xmit = loopback_xmit; |
|
157 dev->hard_header_len = ETH_HLEN; /* 14 */ |
|
158 dev->addr_len = ETH_ALEN; /* 6 */ |
|
159 dev->tx_queue_len = 0; |
|
160 dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
|
161 dev->flags = IFF_LOOPBACK; |
|
162 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
|
163 | NETIF_F_TSO |
|
164 | NETIF_F_NO_CSUM |
|
165 | NETIF_F_HIGHDMA |
|
166 | NETIF_F_LLTX |
|
167 | NETIF_F_NETNS_LOCAL; |
|
168 dev->ethtool_ops = &loopback_ethtool_ops; |
|
169 dev->header_ops = ð_header_ops; |
|
170 dev->init = loopback_dev_init; |
|
171 dev->destructor = loopback_dev_free; |
|
172 } |
|
173 |
|
174 /* Setup and register the loopback device. */ |
|
175 static __net_init int loopback_net_init(struct net *net) |
|
176 { |
|
177 struct net_device *dev; |
|
178 int err; |
|
179 |
|
180 err = -ENOMEM; |
|
181 dev = alloc_netdev(0, "lo", loopback_setup); |
|
182 if (!dev) |
|
183 goto out; |
|
184 |
|
185 dev_net_set(dev, net); |
|
186 err = register_netdev(dev); |
|
187 if (err) |
|
188 goto out_free_netdev; |
|
189 |
|
190 net->loopback_dev = dev; |
|
191 return 0; |
|
192 |
|
193 |
|
194 out_free_netdev: |
|
195 free_netdev(dev); |
|
196 out: |
|
197 if (net == &init_net) |
|
198 panic("loopback: Failed to register netdevice: %d\n", err); |
|
199 return err; |
|
200 } |
|
201 |
|
202 static __net_exit void loopback_net_exit(struct net *net) |
|
203 { |
|
204 struct net_device *dev = net->loopback_dev; |
|
205 |
|
206 unregister_netdev(dev); |
|
207 } |
|
208 |
|
209 static struct pernet_operations __net_initdata loopback_net_ops = { |
|
210 .init = loopback_net_init, |
|
211 .exit = loopback_net_exit, |
|
212 }; |
|
213 |
|
214 static int __init loopback_init(void) |
|
215 { |
|
216 return register_pernet_device(&loopback_net_ops); |
|
217 } |
|
218 |
|
219 /* Loopback is special. It should be initialized before any other network |
|
220 * device and network subsystem. |
|
221 */ |
|
222 fs_initcall(loopback_init); |