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 72 73

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

	skb_orphan(skb);

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

81
	/* it's OK to use per_cpu_ptr() because BHs are off */
82
	pcpu_lstats = dev->ml_priv;
83
	lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
L
Linus Torvalds 已提交
84

E
Eric Dumazet 已提交
85 86 87 88 89 90
	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 已提交
91

92
	return 0;
L
Linus Torvalds 已提交
93 94
}

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

104
	pcpu_lstats = dev->ml_priv;
105
	for_each_possible_cpu(i) {
106
		const struct pcpu_lstats *lb_stats;
L
Linus Torvalds 已提交
107

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

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

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

135 136 137 138 139 140 141 142
static int loopback_dev_init(struct net_device *dev)
{
	struct pcpu_lstats *lstats;

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

143
	dev->ml_priv = lstats;
144 145 146 147 148
	return 0;
}

static void loopback_dev_free(struct net_device *dev)
{
149
	struct pcpu_lstats *lstats = dev->ml_priv;
150 151 152 153 154

	free_percpu(lstats);
	free_netdev(dev);
}

155 156
static const struct net_device_ops loopback_ops = {
	.ndo_init      = loopback_dev_init,
157
	.ndo_start_xmit= loopback_xmit,
158 159 160
	.ndo_get_stats = loopback_get_stats,
};

161
/*
162 163
 * The loopback device is special. There is only one instance
 * per network namespace.
164
 */
165 166 167 168 169 170 171 172
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;
173
	dev->priv_flags	       &= ~IFF_XMIT_DST_RELEASE;
174 175 176 177 178
	dev->features 		= NETIF_F_SG | NETIF_F_FRAGLIST
		| NETIF_F_TSO
		| NETIF_F_NO_CSUM
		| NETIF_F_HIGHDMA
		| NETIF_F_LLTX
179
		| NETIF_F_NETNS_LOCAL;
180
	dev->ethtool_ops	= &loopback_ethtool_ops;
181
	dev->header_ops		= &eth_header_ops;
182 183
	dev->netdev_ops		= &loopback_ops;
	dev->destructor		= loopback_dev_free;
184
}
185

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

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

197
	dev_net_set(dev, net);
198
	err = register_netdev(dev);
199
	if (err)
200
		goto out_free_netdev;
201

202
	net->loopback_dev = dev;
203
	return 0;
204

L
Linus Torvalds 已提交
205

206 207
out_free_netdev:
	free_netdev(dev);
208 209 210 211
out:
	if (net == &init_net)
		panic("loopback: Failed to register netdevice: %d\n", err);
	return err;
212 213
}

214
static __net_exit void loopback_net_exit(struct net *net)
215 216 217 218 219 220
{
	struct net_device *dev = net->loopback_dev;

	unregister_netdev(dev);
}

221 222
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
223 224 225
       .init = loopback_net_init,
       .exit = loopback_net_exit,
};