Blame view
drivers/net/loopback.c
5.36 KB
1da177e4c 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 [PATCH] update Ro... |
10 |
* Authors: Ross Biro |
1da177e4c 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 [NET]: Make the l... |
60 |
#include <net/net_namespace.h> |
5eaa0bd81 loopback: use u64... |
61 |
#include <linux/u64_stats_sync.h> |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
5175c3786 [NET]: reduce per... |
63 |
struct pcpu_lstats { |
5eaa0bd81 loopback: use u64... |
64 65 66 |
u64 packets; u64 bytes; struct u64_stats_sync syncp; |
5175c3786 [NET]: reduce per... |
67 |
}; |
1da177e4c Linux-2.6.12-rc2 |
68 |
|
1da177e4c 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 netdev: convert b... |
73 74 |
static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
75 |
{ |
47d742752 percpu: add __per... |
76 |
struct pcpu_lstats *lb_stats; |
7eebb0b28 loopback: packet ... |
77 |
int len; |
1da177e4c Linux-2.6.12-rc2 |
78 79 |
skb_orphan(skb); |
7eebb0b28 loopback: packet ... |
80 |
skb->protocol = eth_type_trans(skb, dev); |
1da177e4c Linux-2.6.12-rc2 |
81 |
|
9e0db4b12 [NET]: Bring comm... |
82 |
/* it's OK to use per_cpu_ptr() because BHs are off */ |
a7855c78a net: loopback dri... |
83 |
lb_stats = this_cpu_ptr(dev->lstats); |
1da177e4c Linux-2.6.12-rc2 |
84 |
|
7eebb0b28 loopback: packet ... |
85 86 |
len = skb->len; if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { |
5eaa0bd81 loopback: use u64... |
87 |
u64_stats_update_begin(&lb_stats->syncp); |
7eebb0b28 loopback: packet ... |
88 89 |
lb_stats->bytes += len; lb_stats->packets++; |
5eaa0bd81 loopback: use u64... |
90 |
u64_stats_update_end(&lb_stats->syncp); |
caf586e5f net: add a core n... |
91 |
} |
1da177e4c Linux-2.6.12-rc2 |
92 |
|
6ed106549 net: use NETDEV_T... |
93 |
return NETDEV_TX_OK; |
1da177e4c Linux-2.6.12-rc2 |
94 |
} |
28172739f 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 Linux-2.6.12-rc2 |
97 |
{ |
6b10de38f loopback: Impleme... |
98 99 |
u64 bytes = 0; u64 packets = 0; |
1da177e4c Linux-2.6.12-rc2 |
100 |
int i; |
0fed48463 [PATCH] for_each_... |
101 |
for_each_possible_cpu(i) { |
5175c3786 [NET]: reduce per... |
102 |
const struct pcpu_lstats *lb_stats; |
5eaa0bd81 loopback: use u64... |
103 104 |
u64 tbytes, tpackets; unsigned int start; |
1da177e4c Linux-2.6.12-rc2 |
105 |
|
a7855c78a net: loopback dri... |
106 |
lb_stats = per_cpu_ptr(dev->lstats, i); |
5eaa0bd81 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 loopback: use u64... |
112 113 |
bytes += tbytes; packets += tpackets; |
1da177e4c Linux-2.6.12-rc2 |
114 |
} |
5175c3786 [NET]: reduce per... |
115 116 |
stats->rx_packets = packets; stats->tx_packets = packets; |
7eebb0b28 loopback: packet ... |
117 118 |
stats->rx_bytes = bytes; stats->tx_bytes = bytes; |
1da177e4c Linux-2.6.12-rc2 |
119 120 |
return stats; } |
7fa6b0668 [NET] loopback: m... |
121 |
static u32 always_on(struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
122 123 124 |
{ return 1; } |
7282d491e drivers/net: cons... |
125 |
static const struct ethtool_ops loopback_ethtool_ops = { |
7fa6b0668 [NET] loopback: m... |
126 |
.get_link = always_on, |
1da177e4c Linux-2.6.12-rc2 |
127 |
}; |
5f6d88b91 [NET]: Dynamicall... |
128 129 |
static int loopback_dev_init(struct net_device *dev) { |
a7855c78a net: loopback dri... |
130 131 |
dev->lstats = alloc_percpu(struct pcpu_lstats); if (!dev->lstats) |
5f6d88b91 [NET]: Dynamicall... |
132 |
return -ENOMEM; |
5f6d88b91 [NET]: Dynamicall... |
133 134 135 136 137 |
return 0; } static void loopback_dev_free(struct net_device *dev) { |
a7855c78a net: loopback dri... |
138 |
free_percpu(dev->lstats); |
5f6d88b91 [NET]: Dynamicall... |
139 140 |
free_netdev(dev); } |
c02373bf2 netdev: convert l... |
141 142 |
static const struct net_device_ops loopback_ops = { .ndo_init = loopback_dev_init, |
008298231 netdev: add more ... |
143 |
.ndo_start_xmit= loopback_xmit, |
6b10de38f loopback: Impleme... |
144 |
.ndo_get_stats64 = loopback_get_stats64, |
c02373bf2 netdev: convert l... |
145 |
}; |
7fa6b0668 [NET] loopback: m... |
146 |
/* |
9e0db4b12 [NET]: Bring comm... |
147 148 |
* The loopback device is special. There is only one instance * per network namespace. |
7fa6b0668 [NET] loopback: m... |
149 |
*/ |
854d8363f [NET]: Dynamicall... |
150 151 |
static void loopback_setup(struct net_device *dev) { |
854d8363f [NET]: Dynamicall... |
152 |
dev->mtu = (16 * 1024) + 20 + 20 + 12; |
854d8363f [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 [NET]: Dynamicall... |
157 |
dev->flags = IFF_LOOPBACK; |
93f154b59 net: release dst ... |
158 |
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
cf0bdefd4 loopback: convert... |
159 |
dev->hw_features = NETIF_F_ALL_TSO | NETIF_F_UFO; |
854d8363f [NET]: Dynamicall... |
160 |
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
cf0bdefd4 loopback: convert... |
161 162 |
| NETIF_F_ALL_TSO | NETIF_F_UFO |
34324dc2b net: remove NETIF... |
163 |
| NETIF_F_HW_CSUM |
cf0bdefd4 loopback: convert... |
164 |
| NETIF_F_RXCSUM |
854d8363f [NET]: Dynamicall... |
165 166 |
| NETIF_F_HIGHDMA | NETIF_F_LLTX |
0553c891f ip6_pol_route pan... |
167 |
| NETIF_F_NETNS_LOCAL |
eed2a12f1 net: Allow ethtoo... |
168 169 |
| NETIF_F_VLAN_CHALLENGED | NETIF_F_LOOPBACK; |
854d8363f [NET]: Dynamicall... |
170 |
dev->ethtool_ops = &loopback_ethtool_ops; |
3b04ddde0 [NET]: Move hardw... |
171 |
dev->header_ops = ð_header_ops; |
c02373bf2 netdev: convert l... |
172 173 |
dev->netdev_ops = &loopback_ops; dev->destructor = loopback_dev_free; |
854d8363f [NET]: Dynamicall... |
174 |
} |
de3cb747f [NET]: Dynamicall... |
175 |
|
227836495 [NET]: Fix commen... |
176 |
/* Setup and register the loopback device. */ |
4665079cb [NETNS]: Move som... |
177 |
static __net_init int loopback_net_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
178 |
{ |
854d8363f [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 [NET] loopback: P... |
186 |
|
c346dca10 [NET] NETNS: Omit... |
187 |
dev_net_set(dev, net); |
854d8363f [NET]: Dynamicall... |
188 |
err = register_netdev(dev); |
aeed9e82c [NET] loopback: P... |
189 |
if (err) |
854d8363f [NET]: Dynamicall... |
190 |
goto out_free_netdev; |
aeed9e82c [NET] loopback: P... |
191 |
|
2774c7aba [NET]: Make the l... |
192 |
net->loopback_dev = dev; |
9d6dda32c [NETNS]: Don't pa... |
193 |
return 0; |
854d8363f [NET]: Dynamicall... |
194 |
|
1da177e4c Linux-2.6.12-rc2 |
195 |
|
854d8363f [NET]: Dynamicall... |
196 197 |
out_free_netdev: free_netdev(dev); |
9d6dda32c [NETNS]: Don't pa... |
198 |
out: |
09ad9bc75 net: use net_eq t... |
199 |
if (net_eq(net, &init_net)) |
9d6dda32c [NETNS]: Don't pa... |
200 201 202 |
panic("loopback: Failed to register netdevice: %d ", err); return err; |
854d8363f [NET]: Dynamicall... |
203 |
} |
505d4f73d net: Guaranetee t... |
204 205 |
/* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { |
2774c7aba [NET]: Make the l... |
206 |
.init = loopback_net_init, |
2774c7aba [NET]: Make the l... |
207 |
}; |