Blame view

drivers/net/loopback.c 7.08 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
  /*
   * 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...
11
   * Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
   *		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
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
17
   *		Alan Cox	:	Fixed NET3.029 bugs and sped up
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
   *		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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
35
36
37
   */
  #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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
39
  #include <linux/uaccess.h>
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
40
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  #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>
6df014cff   Ezequiel Lara Gomez   Enable tx timesta...
54
  #include <linux/net_tstamp.h>
2774c7aba   Eric W. Biederman   [NET]: Make the l...
55
  #include <net/net_namespace.h>
5eaa0bd81   Eric Dumazet   loopback: use u64...
56
  #include <linux/u64_stats_sync.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

4de83b88c   Mahesh Bandewar   loopback: create ...
58
59
60
61
62
63
  /* blackhole_netdev - a device used for dsts that are marked expired!
   * This is global device (instead of per-net-ns) since it's not needed
   * to be per-ns and gets initialized at boot time.
   */
  struct net_device *blackhole_netdev;
  EXPORT_SYMBOL(blackhole_netdev);
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
64
  /* The higher levels take care of making this non-reentrant (it's
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
   * called with bh's disabled).
   */
61357325f   Stephen Hemminger   netdev: convert b...
67
68
  static netdev_tx_t loopback_xmit(struct sk_buff *skb,
  				 struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  {
47d742752   Tejun Heo   percpu: add __per...
70
  	struct pcpu_lstats *lb_stats;
7eebb0b28   Eric Dumazet   loopback: packet ...
71
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

6df014cff   Ezequiel Lara Gomez   Enable tx timesta...
73
  	skb_tx_timestamp(skb);
4c16128b6   Eric Dumazet   net: loopback: cl...
74
75
76
  
  	/* do not fool net_timestamp_check() with various clock bases */
  	skb->tstamp = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	skb_orphan(skb);
794ed393b   Eric Dumazet   net: loopback: fi...
78
79
80
81
  	/* Before queueing this packet to netif_rx(),
  	 * make sure dst is refcounted.
  	 */
  	skb_dst_force(skb);
7eebb0b28   Eric Dumazet   loopback: packet ...
82
  	skb->protocol = eth_type_trans(skb, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

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

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

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

a7855c78a   Eric Dumazet   net: loopback dri...
108
  		lb_stats = per_cpu_ptr(dev->lstats, i);
5eaa0bd81   Eric Dumazet   loopback: use u64...
109
  		do {
57a7744e0   Eric W. Biederman   net: Replace u64_...
110
  			start = u64_stats_fetch_begin_irq(&lb_stats->syncp);
5eaa0bd81   Eric Dumazet   loopback: use u64...
111
112
  			tbytes = lb_stats->bytes;
  			tpackets = lb_stats->packets;
57a7744e0   Eric W. Biederman   net: Replace u64_...
113
  		} while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start));
5eaa0bd81   Eric Dumazet   loopback: use u64...
114
115
  		bytes   += tbytes;
  		packets += tpackets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  	}
5175c3786   Eric Dumazet   [NET]: reduce per...
117
118
  	stats->rx_packets = packets;
  	stats->tx_packets = packets;
7eebb0b28   Eric Dumazet   loopback: packet ...
119
120
  	stats->rx_bytes   = bytes;
  	stats->tx_bytes   = bytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  }
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
122
  static u32 always_on(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
  {
  	return 1;
  }
7282d491e   Jeff Garzik   drivers/net: cons...
126
  static const struct ethtool_ops loopback_ethtool_ops = {
7fa6b0668   Stephen Hemminger   [NET] loopback: m...
127
  	.get_link		= always_on,
af730342e   Julian Wiedmann   net: loopback: us...
128
  	.get_ts_info		= ethtool_op_get_ts_info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  };
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
130
131
  static int loopback_dev_init(struct net_device *dev)
  {
1c213bd24   WANG Cong   net: introduce ne...
132
  	dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
a7855c78a   Eric Dumazet   net: loopback dri...
133
  	if (!dev->lstats)
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
134
  		return -ENOMEM;
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
135
136
137
138
139
  	return 0;
  }
  
  static void loopback_dev_free(struct net_device *dev)
  {
e05e90702   Eric W. Biederman   net loopback: Set...
140
  	dev_net(dev)->loopback_dev = NULL;
a7855c78a   Eric Dumazet   net: loopback dri...
141
  	free_percpu(dev->lstats);
5f6d88b91   Eric W. Biederman   [NET]: Dynamicall...
142
  }
c02373bf2   Stephen Hemminger   netdev: convert l...
143
  static const struct net_device_ops loopback_ops = {
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
144
145
  	.ndo_init        = loopback_dev_init,
  	.ndo_start_xmit  = loopback_xmit,
6b10de38f   Eric Dumazet   loopback: Impleme...
146
  	.ndo_get_stats64 = loopback_get_stats64,
25f929fbf   WANG Cong   net: allow settin...
147
  	.ndo_set_mac_address = eth_mac_addr,
c02373bf2   Stephen Hemminger   netdev: convert l...
148
  };
4de83b88c   Mahesh Bandewar   loopback: create ...
149
150
151
152
153
154
  static void gen_lo_setup(struct net_device *dev,
  			 unsigned int mtu,
  			 const struct ethtool_ops *eth_ops,
  			 const struct header_ops *hdr_ops,
  			 const struct net_device_ops *dev_ops,
  			 void (*dev_destructor)(struct net_device *dev))
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
155
  {
4de83b88c   Mahesh Bandewar   loopback: create ...
156
  	dev->mtu		= mtu;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
157
  	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
217e6fa24   Willem de Bruijn   net: introduce de...
158
  	dev->min_header_len	= ETH_HLEN;	/* 14	*/
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
159
  	dev->addr_len		= ETH_ALEN;	/* 6	*/
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
160
  	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
161
  	dev->flags		= IFF_LOOPBACK;
e65db2b72   Phil Sutter   net: loopback: co...
162
  	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
028758788   Eric Dumazet   net: better IFF_X...
163
  	netif_keep_dst(dev);
f6c382fc5   Marcelo Ricardo Leitner   loopback: make us...
164
  	dev->hw_features	= NETIF_F_GSO_SOFTWARE;
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
165
  	dev->features		= NETIF_F_SG | NETIF_F_FRAGLIST
f6c382fc5   Marcelo Ricardo Leitner   loopback: make us...
166
  		| NETIF_F_GSO_SOFTWARE
34324dc2b   Michał Mirosław   net: remove NETIF...
167
  		| NETIF_F_HW_CSUM
cf0bdefd4   Michał Mirosław   loopback: convert...
168
  		| NETIF_F_RXCSUM
53692b1de   Tom Herbert   sctp: Rename NETI...
169
  		| NETIF_F_SCTP_CRC
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
170
171
  		| NETIF_F_HIGHDMA
  		| NETIF_F_LLTX
0553c891f   Krishna Kumar   ip6_pol_route pan...
172
  		| NETIF_F_NETNS_LOCAL
eed2a12f1   Mahesh Bandewar   net: Allow ethtoo...
173
174
  		| NETIF_F_VLAN_CHALLENGED
  		| NETIF_F_LOOPBACK;
4de83b88c   Mahesh Bandewar   loopback: create ...
175
176
177
  	dev->ethtool_ops	= eth_ops;
  	dev->header_ops		= hdr_ops;
  	dev->netdev_ops		= dev_ops;
cf124db56   David S. Miller   net: Fix inconsis...
178
  	dev->needs_free_netdev	= true;
4de83b88c   Mahesh Bandewar   loopback: create ...
179
180
181
182
183
184
185
186
187
188
  	dev->priv_destructor	= dev_destructor;
  }
  
  /* The loopback device is special. There is only one instance
   * per network namespace.
   */
  static void loopback_setup(struct net_device *dev)
  {
  	gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,
  		     &loopback_ops, loopback_dev_free);
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
189
  }
de3cb747f   Daniel Lezcano   [NET]: Dynamicall...
190

227836495   Ralf Baechle   [NET]: Fix commen...
191
  /* Setup and register the loopback device. */
4665079cb   Pavel Emelyanov   [NETNS]: Move som...
192
  static __net_init int loopback_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  {
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
194
195
196
197
  	struct net_device *dev;
  	int err;
  
  	err = -ENOMEM;
c835a6773   Tom Gundersen   net: set name_ass...
198
  	dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
199
200
  	if (!dev)
  		goto out;
aeed9e82c   Herbert Xu   [NET] loopback: P...
201

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
202
  	dev_net_set(dev, net);
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
203
  	err = register_netdev(dev);
aeed9e82c   Herbert Xu   [NET] loopback: P...
204
  	if (err)
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
205
  		goto out_free_netdev;
aeed9e82c   Herbert Xu   [NET] loopback: P...
206

1fb9489bf   Pavel Emelyanov   net: Loopback ifi...
207
  	BUG_ON(dev->ifindex != LOOPBACK_IFINDEX);
2774c7aba   Eric W. Biederman   [NET]: Make the l...
208
  	net->loopback_dev = dev;
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
209
  	return 0;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
210

854d8363f   Daniel Lezcano   [NET]: Dynamicall...
211
212
  out_free_netdev:
  	free_netdev(dev);
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
213
  out:
09ad9bc75   Octavian Purdila   net: use net_eq t...
214
  	if (net_eq(net, &init_net))
9d6dda32c   Pavel Emelyanov   [NETNS]: Don't pa...
215
216
217
  		panic("loopback: Failed to register netdevice: %d
  ", err);
  	return err;
854d8363f   Daniel Lezcano   [NET]: Dynamicall...
218
  }
505d4f73d   Eric W. Biederman   net: Guaranetee t...
219
220
  /* Registered in net/core/dev.c */
  struct pernet_operations __net_initdata loopback_net_ops = {
b3407c8e5   Ezequiel Lara Gomez   Cleanup some warn...
221
  	.init = loopback_net_init,
2774c7aba   Eric W. Biederman   [NET]: Make the l...
222
  };
4de83b88c   Mahesh Bandewar   loopback: create ...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  
  /* blackhole netdevice */
  static netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
  					 struct net_device *dev)
  {
  	kfree_skb(skb);
  	net_warn_ratelimited("%s(): Dropping skb.
  ", __func__);
  	return NETDEV_TX_OK;
  }
  
  static const struct net_device_ops blackhole_netdev_ops = {
  	.ndo_start_xmit = blackhole_netdev_xmit,
  };
  
  /* This is a dst-dummy device used specifically for invalidated
   * DSTs and unlike loopback, this is not per-ns.
   */
  static void blackhole_netdev_setup(struct net_device *dev)
  {
  	gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL);
  }
  
  /* Setup and register the blackhole_netdev. */
  static int __init blackhole_netdev_init(void)
  {
  	blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN,
  					blackhole_netdev_setup);
  	if (!blackhole_netdev)
  		return -ENOMEM;
d62962b37   Mahesh Bandewar   loopback: fix loc...
253
  	rtnl_lock();
4de83b88c   Mahesh Bandewar   loopback: create ...
254
255
  	dev_init_scheduler(blackhole_netdev);
  	dev_activate(blackhole_netdev);
d62962b37   Mahesh Bandewar   loopback: fix loc...
256
  	rtnl_unlock();
4de83b88c   Mahesh Bandewar   loopback: create ...
257
258
259
260
261
262
263
264
  
  	blackhole_netdev->flags |= IFF_UP | IFF_RUNNING;
  	dev_net_set(blackhole_netdev, &init_net);
  
  	return 0;
  }
  
  device_initcall(blackhole_netdev_init);