diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/veth.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/veth.c')
-rw-r--r-- | drivers/net/veth.c | 66 |
1 files changed, 34 insertions, 32 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 52af5017c46b..5ec542dd5b50 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netdevice.h> | 11 | #include <linux/netdevice.h> |
12 | #include <linux/slab.h> | ||
12 | #include <linux/ethtool.h> | 13 | #include <linux/ethtool.h> |
13 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
14 | 15 | ||
@@ -34,7 +35,7 @@ struct veth_net_stats { | |||
34 | 35 | ||
35 | struct veth_priv { | 36 | struct veth_priv { |
36 | struct net_device *peer; | 37 | struct net_device *peer; |
37 | struct veth_net_stats *stats; | 38 | struct veth_net_stats __percpu *stats; |
38 | unsigned ip_summed; | 39 | unsigned ip_summed; |
39 | }; | 40 | }; |
40 | 41 | ||
@@ -153,35 +154,24 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
153 | struct net_device *rcv = NULL; | 154 | struct net_device *rcv = NULL; |
154 | struct veth_priv *priv, *rcv_priv; | 155 | struct veth_priv *priv, *rcv_priv; |
155 | struct veth_net_stats *stats, *rcv_stats; | 156 | struct veth_net_stats *stats, *rcv_stats; |
156 | int length, cpu; | 157 | int length; |
157 | |||
158 | skb_orphan(skb); | ||
159 | 158 | ||
160 | priv = netdev_priv(dev); | 159 | priv = netdev_priv(dev); |
161 | rcv = priv->peer; | 160 | rcv = priv->peer; |
162 | rcv_priv = netdev_priv(rcv); | 161 | rcv_priv = netdev_priv(rcv); |
163 | 162 | ||
164 | cpu = smp_processor_id(); | 163 | stats = this_cpu_ptr(priv->stats); |
165 | stats = per_cpu_ptr(priv->stats, cpu); | 164 | rcv_stats = this_cpu_ptr(rcv_priv->stats); |
166 | rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu); | ||
167 | 165 | ||
168 | if (!(rcv->flags & IFF_UP)) | 166 | if (!(rcv->flags & IFF_UP)) |
169 | goto tx_drop; | 167 | goto tx_drop; |
170 | 168 | ||
171 | if (skb->len > (rcv->mtu + MTU_PAD)) | ||
172 | goto rx_drop; | ||
173 | |||
174 | skb->tstamp.tv64 = 0; | ||
175 | skb->pkt_type = PACKET_HOST; | ||
176 | skb->protocol = eth_type_trans(skb, rcv); | ||
177 | if (dev->features & NETIF_F_NO_CSUM) | 169 | if (dev->features & NETIF_F_NO_CSUM) |
178 | skb->ip_summed = rcv_priv->ip_summed; | 170 | skb->ip_summed = rcv_priv->ip_summed; |
179 | 171 | ||
180 | skb->mark = 0; | 172 | length = skb->len + ETH_HLEN; |
181 | secpath_reset(skb); | 173 | if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) |
182 | nf_reset(skb); | 174 | goto rx_drop; |
183 | |||
184 | length = skb->len; | ||
185 | 175 | ||
186 | stats->tx_bytes += length; | 176 | stats->tx_bytes += length; |
187 | stats->tx_packets++; | 177 | stats->tx_packets++; |
@@ -189,7 +179,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
189 | rcv_stats->rx_bytes += length; | 179 | rcv_stats->rx_bytes += length; |
190 | rcv_stats->rx_packets++; | 180 | rcv_stats->rx_packets++; |
191 | 181 | ||
192 | netif_rx(skb); | ||
193 | return NETDEV_TX_OK; | 182 | return NETDEV_TX_OK; |
194 | 183 | ||
195 | tx_drop: | 184 | tx_drop: |
@@ -198,7 +187,6 @@ tx_drop: | |||
198 | return NETDEV_TX_OK; | 187 | return NETDEV_TX_OK; |
199 | 188 | ||
200 | rx_drop: | 189 | rx_drop: |
201 | kfree_skb(skb); | ||
202 | rcv_stats->rx_dropped++; | 190 | rcv_stats->rx_dropped++; |
203 | return NETDEV_TX_OK; | 191 | return NETDEV_TX_OK; |
204 | } | 192 | } |
@@ -275,7 +263,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu) | |||
275 | 263 | ||
276 | static int veth_dev_init(struct net_device *dev) | 264 | static int veth_dev_init(struct net_device *dev) |
277 | { | 265 | { |
278 | struct veth_net_stats *stats; | 266 | struct veth_net_stats __percpu *stats; |
279 | struct veth_priv *priv; | 267 | struct veth_priv *priv; |
280 | 268 | ||
281 | stats = alloc_percpu(struct veth_net_stats); | 269 | stats = alloc_percpu(struct veth_net_stats); |
@@ -337,7 +325,7 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
337 | 325 | ||
338 | static struct rtnl_link_ops veth_link_ops; | 326 | static struct rtnl_link_ops veth_link_ops; |
339 | 327 | ||
340 | static int veth_newlink(struct net_device *dev, | 328 | static int veth_newlink(struct net *src_net, struct net_device *dev, |
341 | struct nlattr *tb[], struct nlattr *data[]) | 329 | struct nlattr *tb[], struct nlattr *data[]) |
342 | { | 330 | { |
343 | int err; | 331 | int err; |
@@ -345,18 +333,17 @@ static int veth_newlink(struct net_device *dev, | |||
345 | struct veth_priv *priv; | 333 | struct veth_priv *priv; |
346 | char ifname[IFNAMSIZ]; | 334 | char ifname[IFNAMSIZ]; |
347 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; | 335 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; |
336 | struct ifinfomsg *ifmp; | ||
337 | struct net *net; | ||
348 | 338 | ||
349 | /* | 339 | /* |
350 | * create and register peer first | 340 | * create and register peer first |
351 | * | ||
352 | * struct ifinfomsg is at the head of VETH_INFO_PEER, but we | ||
353 | * skip it since no info from it is useful yet | ||
354 | */ | 341 | */ |
355 | |||
356 | if (data != NULL && data[VETH_INFO_PEER] != NULL) { | 342 | if (data != NULL && data[VETH_INFO_PEER] != NULL) { |
357 | struct nlattr *nla_peer; | 343 | struct nlattr *nla_peer; |
358 | 344 | ||
359 | nla_peer = data[VETH_INFO_PEER]; | 345 | nla_peer = data[VETH_INFO_PEER]; |
346 | ifmp = nla_data(nla_peer); | ||
360 | err = nla_parse(peer_tb, IFLA_MAX, | 347 | err = nla_parse(peer_tb, IFLA_MAX, |
361 | nla_data(nla_peer) + sizeof(struct ifinfomsg), | 348 | nla_data(nla_peer) + sizeof(struct ifinfomsg), |
362 | nla_len(nla_peer) - sizeof(struct ifinfomsg), | 349 | nla_len(nla_peer) - sizeof(struct ifinfomsg), |
@@ -369,27 +356,41 @@ static int veth_newlink(struct net_device *dev, | |||
369 | return err; | 356 | return err; |
370 | 357 | ||
371 | tbp = peer_tb; | 358 | tbp = peer_tb; |
372 | } else | 359 | } else { |
360 | ifmp = NULL; | ||
373 | tbp = tb; | 361 | tbp = tb; |
362 | } | ||
374 | 363 | ||
375 | if (tbp[IFLA_IFNAME]) | 364 | if (tbp[IFLA_IFNAME]) |
376 | nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); | 365 | nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); |
377 | else | 366 | else |
378 | snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); | 367 | snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); |
379 | 368 | ||
380 | peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp); | 369 | net = rtnl_link_get_net(src_net, tbp); |
381 | if (IS_ERR(peer)) | 370 | if (IS_ERR(net)) |
371 | return PTR_ERR(net); | ||
372 | |||
373 | peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp); | ||
374 | if (IS_ERR(peer)) { | ||
375 | put_net(net); | ||
382 | return PTR_ERR(peer); | 376 | return PTR_ERR(peer); |
377 | } | ||
383 | 378 | ||
384 | if (tbp[IFLA_ADDRESS] == NULL) | 379 | if (tbp[IFLA_ADDRESS] == NULL) |
385 | random_ether_addr(peer->dev_addr); | 380 | random_ether_addr(peer->dev_addr); |
386 | 381 | ||
387 | err = register_netdevice(peer); | 382 | err = register_netdevice(peer); |
383 | put_net(net); | ||
384 | net = NULL; | ||
388 | if (err < 0) | 385 | if (err < 0) |
389 | goto err_register_peer; | 386 | goto err_register_peer; |
390 | 387 | ||
391 | netif_carrier_off(peer); | 388 | netif_carrier_off(peer); |
392 | 389 | ||
390 | err = rtnl_configure_link(peer, ifmp); | ||
391 | if (err < 0) | ||
392 | goto err_configure_peer; | ||
393 | |||
393 | /* | 394 | /* |
394 | * register dev last | 395 | * register dev last |
395 | * | 396 | * |
@@ -431,6 +432,7 @@ static int veth_newlink(struct net_device *dev, | |||
431 | err_register_dev: | 432 | err_register_dev: |
432 | /* nothing to do */ | 433 | /* nothing to do */ |
433 | err_alloc_name: | 434 | err_alloc_name: |
435 | err_configure_peer: | ||
434 | unregister_netdevice(peer); | 436 | unregister_netdevice(peer); |
435 | return err; | 437 | return err; |
436 | 438 | ||
@@ -439,7 +441,7 @@ err_register_peer: | |||
439 | return err; | 441 | return err; |
440 | } | 442 | } |
441 | 443 | ||
442 | static void veth_dellink(struct net_device *dev) | 444 | static void veth_dellink(struct net_device *dev, struct list_head *head) |
443 | { | 445 | { |
444 | struct veth_priv *priv; | 446 | struct veth_priv *priv; |
445 | struct net_device *peer; | 447 | struct net_device *peer; |
@@ -447,8 +449,8 @@ static void veth_dellink(struct net_device *dev) | |||
447 | priv = netdev_priv(dev); | 449 | priv = netdev_priv(dev); |
448 | peer = priv->peer; | 450 | peer = priv->peer; |
449 | 451 | ||
450 | unregister_netdevice(dev); | 452 | unregister_netdevice_queue(dev, head); |
451 | unregister_netdevice(peer); | 453 | unregister_netdevice_queue(peer, head); |
452 | } | 454 | } |
453 | 455 | ||
454 | static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; | 456 | static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; |