loopback.c 5.5 KB
Newer Older
L
Linus Torvalds 已提交
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
 *
10
 * Authors:	Ross Biro
L
Linus Torvalds 已提交
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>
60
#include <net/net_namespace.h>
L
Linus Torvalds 已提交
61

62 63 64
struct pcpu_lstats {
	unsigned long packets;
	unsigned long bytes;
E
Eric Dumazet 已提交
65
	unsigned long drops;
66
};
L
Linus Torvalds 已提交
67 68 69 70 71

/*
 * The higher levels take care of making this non-reentrant (it's
 * called with bh's disabled).
 */
72 73
static netdev_tx_t loopback_xmit(struct sk_buff *skb,
				 struct net_device *dev)
L
Linus Torvalds 已提交
74
{
75 76
	struct pcpu_lstats __percpu *pcpu_lstats;
	struct pcpu_lstats *lb_stats;
E
Eric Dumazet 已提交
77
	int len;
L
Linus Torvalds 已提交
78 79 80

	skb_orphan(skb);

E
Eric Dumazet 已提交
81
	skb->protocol = eth_type_trans(skb, dev);
L
Linus Torvalds 已提交
82

83
	/* it's OK to use per_cpu_ptr() because BHs are off */
84
	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
85
	lb_stats = this_cpu_ptr(pcpu_lstats);
L
Linus Torvalds 已提交
86

E
Eric Dumazet 已提交
87 88 89 90 91 92
	len = skb->len;
	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
		lb_stats->bytes += len;
		lb_stats->packets++;
	} else
		lb_stats->drops++;
L
Linus Torvalds 已提交
93

94
	return NETDEV_TX_OK;
L
Linus Torvalds 已提交
95 96
}

97
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
L
Linus Torvalds 已提交
98
{
99
	const struct pcpu_lstats __percpu *pcpu_lstats;
100
	struct net_device_stats *stats = &dev->stats;
101 102
	unsigned long bytes = 0;
	unsigned long packets = 0;
E
Eric Dumazet 已提交
103
	unsigned long drops = 0;
L
Linus Torvalds 已提交
104 105
	int i;

106
	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
107
	for_each_possible_cpu(i) {
108
		const struct pcpu_lstats *lb_stats;
L
Linus Torvalds 已提交
109

110
		lb_stats = per_cpu_ptr(pcpu_lstats, i);
111 112
		bytes   += lb_stats->bytes;
		packets += lb_stats->packets;
E
Eric Dumazet 已提交
113
		drops   += lb_stats->drops;
L
Linus Torvalds 已提交
114
	}
115 116
	stats->rx_packets = packets;
	stats->tx_packets = packets;
E
Eric Dumazet 已提交
117 118 119 120
	stats->rx_dropped = drops;
	stats->rx_errors  = drops;
	stats->rx_bytes   = bytes;
	stats->tx_bytes   = bytes;
L
Linus Torvalds 已提交
121 122 123
	return stats;
}

124
static u32 always_on(struct net_device *dev)
L
Linus Torvalds 已提交
125 126 127 128
{
	return 1;
}

129
static const struct ethtool_ops loopback_ethtool_ops = {
130
	.get_link		= always_on,
L
Linus Torvalds 已提交
131
	.set_tso		= ethtool_op_set_tso,
132 133 134
	.get_tx_csum		= always_on,
	.get_sg			= always_on,
	.get_rx_csum		= always_on,
L
Linus Torvalds 已提交
135 136
};

137 138
static int loopback_dev_init(struct net_device *dev)
{
139
	struct pcpu_lstats __percpu *lstats;
140 141 142 143 144

	lstats = alloc_percpu(struct pcpu_lstats);
	if (!lstats)
		return -ENOMEM;

145
	dev->ml_priv = (void __force *)lstats;
146 147 148 149 150
	return 0;
}

static void loopback_dev_free(struct net_device *dev)
{
151 152
	struct pcpu_lstats __percpu *lstats =
		(void __percpu __force *)dev->ml_priv;
153 154 155 156 157

	free_percpu(lstats);
	free_netdev(dev);
}

158 159
static const struct net_device_ops loopback_ops = {
	.ndo_init      = loopback_dev_init,
160
	.ndo_start_xmit= loopback_xmit,
161 162 163
	.ndo_get_stats = loopback_get_stats,
};

164
/*
165 166
 * The loopback device is special. There is only one instance
 * per network namespace.
167
 */
168 169 170 171 172 173 174 175
static void loopback_setup(struct net_device *dev)
{
	dev->mtu		= (16 * 1024) + 20 + 20 + 12;
	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
	dev->addr_len		= ETH_ALEN;	/* 6	*/
	dev->tx_queue_len	= 0;
	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
	dev->flags		= IFF_LOOPBACK;
176
	dev->priv_flags	       &= ~IFF_XMIT_DST_RELEASE;
177 178 179 180 181
	dev->features 		= NETIF_F_SG | NETIF_F_FRAGLIST
		| NETIF_F_TSO
		| NETIF_F_NO_CSUM
		| NETIF_F_HIGHDMA
		| NETIF_F_LLTX
182
		| NETIF_F_NETNS_LOCAL;
183
	dev->ethtool_ops	= &loopback_ethtool_ops;
184
	dev->header_ops		= &eth_header_ops;
185 186
	dev->netdev_ops		= &loopback_ops;
	dev->destructor		= loopback_dev_free;
187
}
188

189
/* Setup and register the loopback device. */
190
static __net_init int loopback_net_init(struct net *net)
L
Linus Torvalds 已提交
191
{
192 193 194 195 196 197 198
	struct net_device *dev;
	int err;

	err = -ENOMEM;
	dev = alloc_netdev(0, "lo", loopback_setup);
	if (!dev)
		goto out;
199

200
	dev_net_set(dev, net);
201
	err = register_netdev(dev);
202
	if (err)
203
		goto out_free_netdev;
204

205
	net->loopback_dev = dev;
206
	return 0;
207

L
Linus Torvalds 已提交
208

209 210
out_free_netdev:
	free_netdev(dev);
211
out:
O
Octavian Purdila 已提交
212
	if (net_eq(net, &init_net))
213 214
		panic("loopback: Failed to register netdevice: %d\n", err);
	return err;
215 216
}

217 218
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
219 220
       .init = loopback_net_init,
};