Blame view
drivers/net/loopback.c
7.08 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c 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 [PATCH] update Ro... |
11 |
* Authors: Ross Biro |
1da177e4c 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 Cleanup some warn... |
17 |
* Alan Cox : Fixed NET3.029 bugs and sped up |
1da177e4c 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 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 Linux-2.6.12-rc2 |
38 |
|
7c0f6ba68 Replace <asm/uacc... |
39 |
#include <linux/uaccess.h> |
b3407c8e5 Cleanup some warn... |
40 |
#include <linux/io.h> |
1da177e4c 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 Enable tx timesta... |
54 |
#include <linux/net_tstamp.h> |
2774c7aba [NET]: Make the l... |
55 |
#include <net/net_namespace.h> |
5eaa0bd81 loopback: use u64... |
56 |
#include <linux/u64_stats_sync.h> |
1da177e4c Linux-2.6.12-rc2 |
57 |
|
4de83b88c 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 Cleanup some warn... |
64 |
/* The higher levels take care of making this non-reentrant (it's |
1da177e4c Linux-2.6.12-rc2 |
65 66 |
* called with bh's disabled). */ |
61357325f netdev: convert b... |
67 68 |
static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
69 |
{ |
47d742752 percpu: add __per... |
70 |
struct pcpu_lstats *lb_stats; |
7eebb0b28 loopback: packet ... |
71 |
int len; |
1da177e4c Linux-2.6.12-rc2 |
72 |
|
6df014cff Enable tx timesta... |
73 |
skb_tx_timestamp(skb); |
4c16128b6 net: loopback: cl... |
74 75 76 |
/* do not fool net_timestamp_check() with various clock bases */ skb->tstamp = 0; |
1da177e4c Linux-2.6.12-rc2 |
77 |
skb_orphan(skb); |
794ed393b net: loopback: fi... |
78 79 80 81 |
/* Before queueing this packet to netif_rx(), * make sure dst is refcounted. */ skb_dst_force(skb); |
7eebb0b28 loopback: packet ... |
82 |
skb->protocol = eth_type_trans(skb, dev); |
1da177e4c Linux-2.6.12-rc2 |
83 |
|
9e0db4b12 [NET]: Bring comm... |
84 |
/* it's OK to use per_cpu_ptr() because BHs are off */ |
a7855c78a net: loopback dri... |
85 |
lb_stats = this_cpu_ptr(dev->lstats); |
1da177e4c Linux-2.6.12-rc2 |
86 |
|
7eebb0b28 loopback: packet ... |
87 88 |
len = skb->len; if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { |
5eaa0bd81 loopback: use u64... |
89 |
u64_stats_update_begin(&lb_stats->syncp); |
7eebb0b28 loopback: packet ... |
90 91 |
lb_stats->bytes += len; lb_stats->packets++; |
5eaa0bd81 loopback: use u64... |
92 |
u64_stats_update_end(&lb_stats->syncp); |
caf586e5f net: add a core n... |
93 |
} |
1da177e4c Linux-2.6.12-rc2 |
94 |
|
6ed106549 net: use NETDEV_T... |
95 |
return NETDEV_TX_OK; |
1da177e4c Linux-2.6.12-rc2 |
96 |
} |
bc1f44709 net: make ndo_get... |
97 98 |
static void loopback_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) |
1da177e4c Linux-2.6.12-rc2 |
99 |
{ |
6b10de38f loopback: Impleme... |
100 101 |
u64 bytes = 0; u64 packets = 0; |
1da177e4c Linux-2.6.12-rc2 |
102 |
int i; |
0fed48463 [PATCH] for_each_... |
103 |
for_each_possible_cpu(i) { |
5175c3786 [NET]: reduce per... |
104 |
const struct pcpu_lstats *lb_stats; |
5eaa0bd81 loopback: use u64... |
105 106 |
u64 tbytes, tpackets; unsigned int start; |
1da177e4c Linux-2.6.12-rc2 |
107 |
|
a7855c78a net: loopback dri... |
108 |
lb_stats = per_cpu_ptr(dev->lstats, i); |
5eaa0bd81 loopback: use u64... |
109 |
do { |
57a7744e0 net: Replace u64_... |
110 |
start = u64_stats_fetch_begin_irq(&lb_stats->syncp); |
5eaa0bd81 loopback: use u64... |
111 112 |
tbytes = lb_stats->bytes; tpackets = lb_stats->packets; |
57a7744e0 net: Replace u64_... |
113 |
} while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); |
5eaa0bd81 loopback: use u64... |
114 115 |
bytes += tbytes; packets += tpackets; |
1da177e4c Linux-2.6.12-rc2 |
116 |
} |
5175c3786 [NET]: reduce per... |
117 118 |
stats->rx_packets = packets; stats->tx_packets = packets; |
7eebb0b28 loopback: packet ... |
119 120 |
stats->rx_bytes = bytes; stats->tx_bytes = bytes; |
1da177e4c Linux-2.6.12-rc2 |
121 |
} |
7fa6b0668 [NET] loopback: m... |
122 |
static u32 always_on(struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 |
{ return 1; } |
7282d491e drivers/net: cons... |
126 |
static const struct ethtool_ops loopback_ethtool_ops = { |
7fa6b0668 [NET] loopback: m... |
127 |
.get_link = always_on, |
af730342e net: loopback: us... |
128 |
.get_ts_info = ethtool_op_get_ts_info, |
1da177e4c Linux-2.6.12-rc2 |
129 |
}; |
5f6d88b91 [NET]: Dynamicall... |
130 131 |
static int loopback_dev_init(struct net_device *dev) { |
1c213bd24 net: introduce ne... |
132 |
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); |
a7855c78a net: loopback dri... |
133 |
if (!dev->lstats) |
5f6d88b91 [NET]: Dynamicall... |
134 |
return -ENOMEM; |
5f6d88b91 [NET]: Dynamicall... |
135 136 137 138 139 |
return 0; } static void loopback_dev_free(struct net_device *dev) { |
e05e90702 net loopback: Set... |
140 |
dev_net(dev)->loopback_dev = NULL; |
a7855c78a net: loopback dri... |
141 |
free_percpu(dev->lstats); |
5f6d88b91 [NET]: Dynamicall... |
142 |
} |
c02373bf2 netdev: convert l... |
143 |
static const struct net_device_ops loopback_ops = { |
b3407c8e5 Cleanup some warn... |
144 145 |
.ndo_init = loopback_dev_init, .ndo_start_xmit = loopback_xmit, |
6b10de38f loopback: Impleme... |
146 |
.ndo_get_stats64 = loopback_get_stats64, |
25f929fbf net: allow settin... |
147 |
.ndo_set_mac_address = eth_mac_addr, |
c02373bf2 netdev: convert l... |
148 |
}; |
4de83b88c 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 [NET]: Dynamicall... |
155 |
{ |
4de83b88c loopback: create ... |
156 |
dev->mtu = mtu; |
854d8363f [NET]: Dynamicall... |
157 |
dev->hard_header_len = ETH_HLEN; /* 14 */ |
217e6fa24 net: introduce de... |
158 |
dev->min_header_len = ETH_HLEN; /* 14 */ |
854d8363f [NET]: Dynamicall... |
159 |
dev->addr_len = ETH_ALEN; /* 6 */ |
854d8363f [NET]: Dynamicall... |
160 |
dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
854d8363f [NET]: Dynamicall... |
161 |
dev->flags = IFF_LOOPBACK; |
e65db2b72 net: loopback: co... |
162 |
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; |
028758788 net: better IFF_X... |
163 |
netif_keep_dst(dev); |
f6c382fc5 loopback: make us... |
164 |
dev->hw_features = NETIF_F_GSO_SOFTWARE; |
b3407c8e5 Cleanup some warn... |
165 |
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
f6c382fc5 loopback: make us... |
166 |
| NETIF_F_GSO_SOFTWARE |
34324dc2b net: remove NETIF... |
167 |
| NETIF_F_HW_CSUM |
cf0bdefd4 loopback: convert... |
168 |
| NETIF_F_RXCSUM |
53692b1de sctp: Rename NETI... |
169 |
| NETIF_F_SCTP_CRC |
854d8363f [NET]: Dynamicall... |
170 171 |
| NETIF_F_HIGHDMA | NETIF_F_LLTX |
0553c891f ip6_pol_route pan... |
172 |
| NETIF_F_NETNS_LOCAL |
eed2a12f1 net: Allow ethtoo... |
173 174 |
| NETIF_F_VLAN_CHALLENGED | NETIF_F_LOOPBACK; |
4de83b88c loopback: create ... |
175 176 177 |
dev->ethtool_ops = eth_ops; dev->header_ops = hdr_ops; dev->netdev_ops = dev_ops; |
cf124db56 net: Fix inconsis... |
178 |
dev->needs_free_netdev = true; |
4de83b88c 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, ð_header_ops, &loopback_ops, loopback_dev_free); |
854d8363f [NET]: Dynamicall... |
189 |
} |
de3cb747f [NET]: Dynamicall... |
190 |
|
227836495 [NET]: Fix commen... |
191 |
/* Setup and register the loopback device. */ |
4665079cb [NETNS]: Move som... |
192 |
static __net_init int loopback_net_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
193 |
{ |
854d8363f [NET]: Dynamicall... |
194 195 196 197 |
struct net_device *dev; int err; err = -ENOMEM; |
c835a6773 net: set name_ass... |
198 |
dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup); |
854d8363f [NET]: Dynamicall... |
199 200 |
if (!dev) goto out; |
aeed9e82c [NET] loopback: P... |
201 |
|
c346dca10 [NET] NETNS: Omit... |
202 |
dev_net_set(dev, net); |
854d8363f [NET]: Dynamicall... |
203 |
err = register_netdev(dev); |
aeed9e82c [NET] loopback: P... |
204 |
if (err) |
854d8363f [NET]: Dynamicall... |
205 |
goto out_free_netdev; |
aeed9e82c [NET] loopback: P... |
206 |
|
1fb9489bf net: Loopback ifi... |
207 |
BUG_ON(dev->ifindex != LOOPBACK_IFINDEX); |
2774c7aba [NET]: Make the l... |
208 |
net->loopback_dev = dev; |
9d6dda32c [NETNS]: Don't pa... |
209 |
return 0; |
854d8363f [NET]: Dynamicall... |
210 |
|
854d8363f [NET]: Dynamicall... |
211 212 |
out_free_netdev: free_netdev(dev); |
9d6dda32c [NETNS]: Don't pa... |
213 |
out: |
09ad9bc75 net: use net_eq t... |
214 |
if (net_eq(net, &init_net)) |
9d6dda32c [NETNS]: Don't pa... |
215 216 217 |
panic("loopback: Failed to register netdevice: %d ", err); return err; |
854d8363f [NET]: Dynamicall... |
218 |
} |
505d4f73d net: Guaranetee t... |
219 220 |
/* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { |
b3407c8e5 Cleanup some warn... |
221 |
.init = loopback_net_init, |
2774c7aba [NET]: Make the l... |
222 |
}; |
4de83b88c 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 loopback: fix loc... |
253 |
rtnl_lock(); |
4de83b88c loopback: create ... |
254 255 |
dev_init_scheduler(blackhole_netdev); dev_activate(blackhole_netdev); |
d62962b37 loopback: fix loc... |
256 |
rtnl_unlock(); |
4de83b88c 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); |