Blame view

drivers/net/loopback.c 5.36 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		Pseudo-driver for the loopback interface.
   *
   * Version:	@(#)loopback.c	1.0.4b	08/16/93
   *
02c30a84e   Jesper Juhl   [PATCH] update Ro...
10
   * Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
   *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
   *		Donald Becker, <becker@scyld.com>
   *
   *		Alan Cox	:	Fixed oddments for NET3.014
   *		Alan Cox	:	Rejig for NET3.029 snap #3
   *		Alan Cox	: 	Fixed NET3.029 bugs and sped up
   *		Larry McVoy	:	Tiny tweak to double performance
   *		Alan Cox	:	Backed out LMV's tweak - the linux mm
   *					can't take it...
   *              Michael Griffith:       Don't bother computing the checksums
   *                                      on packets received on the loopback
   *                                      interface.
   *		Alexey Kuznetsov:	Potential hang under some extreme
   *					cases removed.
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   */
  #include <linux/kernel.h>
  #include <linux/jiffies.h>
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/fs.h>
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/socket.h>
  #include <linux/errno.h>
  #include <linux/fcntl.h>
  #include <linux/in.h>
  #include <linux/init.h>
  
  #include <asm/system.h>
  #include <asm/uaccess.h>
  #include <asm/io.h>
  
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/skbuff.h>
  #include <linux/ethtool.h>
  #include <net/sock.h>
  #include <net/checksum.h>
  #include <linux/if_ether.h>	/* For the statistics structure. */
  #include <linux/if_arp.h>	/* For ARPHRD_ETHER */
  #include <linux/ip.h>
  #include <linux/tcp.h>
  #include <linux/percpu.h>
2774c7aba   Eric W. Biederman   [NET]: Make the l...
60
  #include <net/net_namespace.h>
5eaa0bd81   Eric Dumazet   loopback: use u64...
61
  #include <linux/u64_stats_sync.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

5175c3786   Eric Dumazet   [NET]: reduce per...
63
  struct pcpu_lstats {
5eaa0bd81   Eric Dumazet   loopback: use u64...
64
65
66
  	u64			packets;
  	u64			bytes;
  	struct u64_stats_sync	syncp;
5175c3786   Eric Dumazet   [NET]: reduce per...
67
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
  /*
   * The higher levels take care of making this non-reentrant (it's
   * called with bh's disabled).
   */
61357325f   Stephen Hemminger   netdev: convert b...
73
74
  static netdev_tx_t loopback_xmit(struct sk_buff *skb,
  				 struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  {
47d742752   Tejun Heo   percpu: add __per...
76
  	struct pcpu_lstats *lb_stats;
7eebb0b28   Eric Dumazet   loopback: packet ...
77
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
  
  	skb_orphan(skb);
7eebb0b28   Eric Dumazet   loopback: packet ...
80
  	skb->protocol = eth_type_trans(skb, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

9e0db4b12   Eric W. Biederman   [NET]: Bring comm...
82
  	/* it's OK to use per_cpu_ptr() because BHs are off */
a7855c78a   Eric Dumazet   net: loopback dri...
83
  	lb_stats = this_cpu_ptr(dev->lstats);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

7eebb0b28   Eric Dumazet   loopback: packet ...
85
86
  	len = skb->len;
  	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
5eaa0bd81   Eric Dumazet   loopback: use u64...
87
  		u64_stats_update_begin(&lb_stats->syncp);
7eebb0b28   Eric Dumazet   loopback: packet ...
88
89
  		lb_stats->bytes += len;
  		lb_stats->packets++;
5eaa0bd81   Eric Dumazet   loopback: use u64...
90
  		u64_stats_update_end(&lb_stats->syncp);
caf586e5f   Eric Dumazet   net: add a core n...
91
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

6ed106549   Patrick McHardy   net: use NETDEV_T...
93
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  }
28172739f   Eric Dumazet   net: fix 64 bit c...
95
96
  static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
  						      struct rtnl_link_stats64 *stats)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  {
6b10de38f   Eric Dumazet   loopback: Impleme...
98
99
  	u64 bytes = 0;
  	u64 packets = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  	int i;
0fed48463   KAMEZAWA Hiroyuki   [PATCH] for_each_...
101
  	for_each_possible_cpu(i) {
5175c3786   Eric Dumazet   [NET]: reduce per...
102
  		const struct pcpu_lstats *lb_stats;
5eaa0bd81   Eric Dumazet   loopback: use u64...
103
104
  		u64 tbytes, tpackets;
  		unsigned int start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

a7855c78a   Eric Dumazet   net: loopback dri...
106
  		lb_stats = per_cpu_ptr(dev->lstats, i);
5eaa0bd81   Eric Dumazet   loopback: use u64...
107
108
109
110
111
  		do {
  			start = u64_stats_fetch_begin(&lb_stats->syncp);
  			tbytes = lb_stats->bytes;
  			tpackets = lb_stats->packets;
  		} while (u64_stats_fetch_retry(&lb_stats->syncp, start));
5eaa0bd81   Eric Dumazet   loopback: use u64...
112
113
  		bytes   += tbytes;
  		packets += tpackets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	}
5175c3786   Eric Dumazet   [NET]: reduce per...
115
116
  	stats->rx_packets = packets;
  	stats->tx_packets = packets;
7eebb0b28   Eric Dumazet   loopback: packet ...
117
118
  	stats->rx_bytes   = bytes;
  	stats->tx_bytes   = bytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  	return stats;
  }
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
121
  static u32 always_on(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
  {
  	return 1;
  }
7282d491e   Jeff Garzik   drivers/net: cons...
125
  static const struct ethtool_ops loopback_ethtool_ops = {
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
126
  	.get_link		= always_on,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  };
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
128
129
  static int loopback_dev_init(struct net_device *dev)
  {
a7855c78a   Eric Dumazet   net: loopback dri...
130
131
  	dev->lstats = alloc_percpu(struct pcpu_lstats);
  	if (!dev->lstats)
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
132
  		return -ENOMEM;
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
133
134
135
136
137
  	return 0;
  }
  
  static void loopback_dev_free(struct net_device *dev)
  {
a7855c78a   Eric Dumazet   net: loopback dri...
138
  	free_percpu(dev->lstats);
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
139
140
  	free_netdev(dev);
  }
c02373bf2   Stephen Hemminger   netdev: convert l...
141
142
  static const struct net_device_ops loopback_ops = {
  	.ndo_init      = loopback_dev_init,
008298231   Stephen Hemminger   netdev: add more ...
143
  	.ndo_start_xmit= loopback_xmit,
6b10de38f   Eric Dumazet   loopback: Impleme...
144
  	.ndo_get_stats64 = loopback_get_stats64,
c02373bf2   Stephen Hemminger   netdev: convert l...
145
  };
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
146
  /*
9e0db4b12   Eric W. Biederman   [NET]: Bring comm...
147
148
   * The loopback device is special. There is only one instance
   * per network namespace.
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
149
   */
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
150
151
  static void loopback_setup(struct net_device *dev)
  {
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
152
  	dev->mtu		= (16 * 1024) + 20 + 20 + 12;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
153
154
155
156
  	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
  	dev->addr_len		= ETH_ALEN;	/* 6	*/
  	dev->tx_queue_len	= 0;
  	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
157
  	dev->flags		= IFF_LOOPBACK;
93f154b59   Eric Dumazet   net: release dst ...
158
  	dev->priv_flags	       &= ~IFF_XMIT_DST_RELEASE;
cf0bdefd4   Michał Mirosław   loopback: convert...
159
  	dev->hw_features	= NETIF_F_ALL_TSO | NETIF_F_UFO;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
160
  	dev->features 		= NETIF_F_SG | NETIF_F_FRAGLIST
cf0bdefd4   Michał Mirosław   loopback: convert...
161
162
  		| NETIF_F_ALL_TSO
  		| NETIF_F_UFO
34324dc2b   Michał Mirosław   net: remove NETIF...
163
  		| NETIF_F_HW_CSUM
cf0bdefd4   Michał Mirosław   loopback: convert...
164
  		| NETIF_F_RXCSUM
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
165
166
  		| NETIF_F_HIGHDMA
  		| NETIF_F_LLTX
0553c891f   Krishna Kumar   ip6_pol_route pan...
167
  		| NETIF_F_NETNS_LOCAL
eed2a12f1   Mahesh Bandewar   net: Allow ethtoo...
168
169
  		| NETIF_F_VLAN_CHALLENGED
  		| NETIF_F_LOOPBACK;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
170
  	dev->ethtool_ops	= &loopback_ethtool_ops;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
171
  	dev->header_ops		= &eth_header_ops;
c02373bf2   Stephen Hemminger   netdev: convert l...
172
173
  	dev->netdev_ops		= &loopback_ops;
  	dev->destructor		= loopback_dev_free;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
174
  }
de3cb747f   Daniel Lezcano   [NET]: Dynamicall...
175

227836495   Ralf Baechle   [NET]: Fix commen...
176
  /* Setup and register the loopback device. */
4665079cb   Pavel Emelyanov   [NETNS]: Move som...
177
  static __net_init int loopback_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  {
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
179
180
181
182
183
184
185
  	struct net_device *dev;
  	int err;
  
  	err = -ENOMEM;
  	dev = alloc_netdev(0, "lo", loopback_setup);
  	if (!dev)
  		goto out;
aeed9e82c   Herbert Xu   [NET] loopback: P...
186

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
187
  	dev_net_set(dev, net);
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
188
  	err = register_netdev(dev);
aeed9e82c   Herbert Xu   [NET] loopback: P...
189
  	if (err)
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
190
  		goto out_free_netdev;
aeed9e82c   Herbert Xu   [NET] loopback: P...
191

2774c7aba   Eric W. Biederman   [NET]: Make the l...
192
  	net->loopback_dev = dev;
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
193
  	return 0;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
194

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

854d8363f   Daniel Lezcano   [NET]: Dynamicall...
196
197
  out_free_netdev:
  	free_netdev(dev);
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
198
  out:
09ad9bc75   Octavian Purdila   net: use net_eq t...
199
  	if (net_eq(net, &init_net))
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
200
201
202
  		panic("loopback: Failed to register netdevice: %d
  ", err);
  	return err;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
203
  }
505d4f73d   Eric W. Biederman   net: Guaranetee t...
204
205
  /* Registered in net/core/dev.c */
  struct pernet_operations __net_initdata loopback_net_ops = {
2774c7aba   Eric W. Biederman   [NET]: Make the l...
206
         .init = loopback_net_init,
2774c7aba   Eric W. Biederman   [NET]: Make the l...
207
  };