equal
deleted
inserted
replaced
74 |
74 |
75 skb_orphan(skb); |
75 skb_orphan(skb); |
76 |
76 |
77 skb->protocol = eth_type_trans(skb,dev); |
77 skb->protocol = eth_type_trans(skb,dev); |
78 |
78 |
79 dev->last_rx = jiffies; |
|
80 |
|
81 /* it's OK to use per_cpu_ptr() because BHs are off */ |
79 /* it's OK to use per_cpu_ptr() because BHs are off */ |
82 pcpu_lstats = dev->ml_priv; |
80 pcpu_lstats = dev->ml_priv; |
83 lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); |
81 lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); |
84 lb_stats->bytes += skb->len; |
82 lb_stats->bytes += skb->len; |
85 lb_stats->packets++; |
83 lb_stats->packets++; |
87 netif_rx(skb); |
85 netif_rx(skb); |
88 |
86 |
89 return 0; |
87 return 0; |
90 } |
88 } |
91 |
89 |
92 static struct net_device_stats *get_stats(struct net_device *dev) |
90 static struct net_device_stats *loopback_get_stats(struct net_device *dev) |
93 { |
91 { |
94 const struct pcpu_lstats *pcpu_lstats; |
92 const struct pcpu_lstats *pcpu_lstats; |
95 struct net_device_stats *stats = &dev->stats; |
93 struct net_device_stats *stats = &dev->stats; |
96 unsigned long bytes = 0; |
94 unsigned long bytes = 0; |
97 unsigned long packets = 0; |
95 unsigned long packets = 0; |
143 |
141 |
144 free_percpu(lstats); |
142 free_percpu(lstats); |
145 free_netdev(dev); |
143 free_netdev(dev); |
146 } |
144 } |
147 |
145 |
|
146 static const struct net_device_ops loopback_ops = { |
|
147 .ndo_init = loopback_dev_init, |
|
148 .ndo_start_xmit= loopback_xmit, |
|
149 .ndo_get_stats = loopback_get_stats, |
|
150 }; |
|
151 |
148 /* |
152 /* |
149 * The loopback device is special. There is only one instance |
153 * The loopback device is special. There is only one instance |
150 * per network namespace. |
154 * per network namespace. |
151 */ |
155 */ |
152 static void loopback_setup(struct net_device *dev) |
156 static void loopback_setup(struct net_device *dev) |
153 { |
157 { |
154 dev->get_stats = &get_stats; |
|
155 dev->mtu = (16 * 1024) + 20 + 20 + 12; |
158 dev->mtu = (16 * 1024) + 20 + 20 + 12; |
156 dev->hard_start_xmit = loopback_xmit; |
|
157 dev->hard_header_len = ETH_HLEN; /* 14 */ |
159 dev->hard_header_len = ETH_HLEN; /* 14 */ |
158 dev->addr_len = ETH_ALEN; /* 6 */ |
160 dev->addr_len = ETH_ALEN; /* 6 */ |
159 dev->tx_queue_len = 0; |
161 dev->tx_queue_len = 0; |
160 dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
162 dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
161 dev->flags = IFF_LOOPBACK; |
163 dev->flags = IFF_LOOPBACK; |
165 | NETIF_F_HIGHDMA |
167 | NETIF_F_HIGHDMA |
166 | NETIF_F_LLTX |
168 | NETIF_F_LLTX |
167 | NETIF_F_NETNS_LOCAL; |
169 | NETIF_F_NETNS_LOCAL; |
168 dev->ethtool_ops = &loopback_ethtool_ops; |
170 dev->ethtool_ops = &loopback_ethtool_ops; |
169 dev->header_ops = ð_header_ops; |
171 dev->header_ops = ð_header_ops; |
170 dev->init = loopback_dev_init; |
172 dev->netdev_ops = &loopback_ops; |
171 dev->destructor = loopback_dev_free; |
173 dev->destructor = loopback_dev_free; |
172 } |
174 } |
173 |
175 |
174 /* Setup and register the loopback device. */ |
176 /* Setup and register the loopback device. */ |
175 static __net_init int loopback_net_init(struct net *net) |
177 static __net_init int loopback_net_init(struct net *net) |
176 { |
178 { |
204 struct net_device *dev = net->loopback_dev; |
206 struct net_device *dev = net->loopback_dev; |
205 |
207 |
206 unregister_netdev(dev); |
208 unregister_netdev(dev); |
207 } |
209 } |
208 |
210 |
209 static struct pernet_operations __net_initdata loopback_net_ops = { |
211 /* Registered in net/core/dev.c */ |
|
212 struct pernet_operations __net_initdata loopback_net_ops = { |
210 .init = loopback_net_init, |
213 .init = loopback_net_init, |
211 .exit = loopback_net_exit, |
214 .exit = loopback_net_exit, |
212 }; |
215 }; |
213 |
|
214 static int __init loopback_init(void) |
|
215 { |
|
216 return register_pernet_device(&loopback_net_ops); |
|
217 } |
|
218 |
|
219 /* Loopback is special. It should be initialized before any other network |
|
220 * device and network subsystem. |
|
221 */ |
|
222 fs_initcall(loopback_init); |
|