Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / drivers / net / veth.c
index 015db1c..5ec542d 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/netdevice.h>
+#include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
 
@@ -34,7 +35,7 @@ struct veth_net_stats {
 
 struct veth_priv {
        struct net_device *peer;
-       struct veth_net_stats *stats;
+       struct veth_net_stats __percpu *stats;
        unsigned ip_summed;
 };
 
@@ -129,7 +130,7 @@ static int veth_set_tx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
-static struct ethtool_ops veth_ethtool_ops = {
+static const struct ethtool_ops veth_ethtool_ops = {
        .get_settings           = veth_get_settings,
        .get_drvinfo            = veth_get_drvinfo,
        .get_link               = ethtool_op_get_link,
@@ -148,41 +149,29 @@ static struct ethtool_ops veth_ethtool_ops = {
  * xmit
  */
 
-static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_device *rcv = NULL;
        struct veth_priv *priv, *rcv_priv;
        struct veth_net_stats *stats, *rcv_stats;
-       int length, cpu;
-
-       skb_orphan(skb);
+       int length;
 
        priv = netdev_priv(dev);
        rcv = priv->peer;
        rcv_priv = netdev_priv(rcv);
 
-       cpu = smp_processor_id();
-       stats = per_cpu_ptr(priv->stats, cpu);
-       rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu);
+       stats = this_cpu_ptr(priv->stats);
+       rcv_stats = this_cpu_ptr(rcv_priv->stats);
 
        if (!(rcv->flags & IFF_UP))
                goto tx_drop;
 
-       if (skb->len > (rcv->mtu + MTU_PAD))
-               goto rx_drop;
-
-       skb->pkt_type = PACKET_HOST;
-       skb->protocol = eth_type_trans(skb, rcv);
        if (dev->features & NETIF_F_NO_CSUM)
                skb->ip_summed = rcv_priv->ip_summed;
 
-       dst_release(skb->dst);
-       skb->dst = NULL;
-       skb->mark = 0;
-       secpath_reset(skb);
-       nf_reset(skb);
-
-       length = skb->len;
+       length = skb->len + ETH_HLEN;
+       if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
+               goto rx_drop;
 
        stats->tx_bytes += length;
        stats->tx_packets++;
@@ -190,18 +179,16 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
        rcv_stats->rx_bytes += length;
        rcv_stats->rx_packets++;
 
-       netif_rx(skb);
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_drop:
        kfree_skb(skb);
        stats->tx_dropped++;
-       return 0;
+       return NETDEV_TX_OK;
 
 rx_drop:
-       kfree_skb(skb);
        rcv_stats->rx_dropped++;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -211,32 +198,29 @@ rx_drop:
 static struct net_device_stats *veth_get_stats(struct net_device *dev)
 {
        struct veth_priv *priv;
-       struct net_device_stats *dev_stats;
        int cpu;
-       struct veth_net_stats *stats;
+       struct veth_net_stats *stats, total = {0};
 
        priv = netdev_priv(dev);
-       dev_stats = &dev->stats;
-
-       dev_stats->rx_packets = 0;
-       dev_stats->tx_packets = 0;
-       dev_stats->rx_bytes = 0;
-       dev_stats->tx_bytes = 0;
-       dev_stats->tx_dropped = 0;
-       dev_stats->rx_dropped = 0;
 
-       for_each_online_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                stats = per_cpu_ptr(priv->stats, cpu);
 
-               dev_stats->rx_packets += stats->rx_packets;
-               dev_stats->tx_packets += stats->tx_packets;
-               dev_stats->rx_bytes += stats->rx_bytes;
-               dev_stats->tx_bytes += stats->tx_bytes;
-               dev_stats->tx_dropped += stats->tx_dropped;
-               dev_stats->rx_dropped += stats->rx_dropped;
+               total.rx_packets += stats->rx_packets;
+               total.tx_packets += stats->tx_packets;
+               total.rx_bytes   += stats->rx_bytes;
+               total.tx_bytes   += stats->tx_bytes;
+               total.tx_dropped += stats->tx_dropped;
+               total.rx_dropped += stats->rx_dropped;
        }
-
-       return dev_stats;
+       dev->stats.rx_packets = total.rx_packets;
+       dev->stats.tx_packets = total.tx_packets;
+       dev->stats.rx_bytes   = total.rx_bytes;
+       dev->stats.tx_bytes   = total.tx_bytes;
+       dev->stats.tx_dropped = total.tx_dropped;
+       dev->stats.rx_dropped = total.rx_dropped;
+
+       return &dev->stats;
 }
 
 static int veth_open(struct net_device *dev)
@@ -279,7 +263,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
 
 static int veth_dev_init(struct net_device *dev)
 {
-       struct veth_net_stats *stats;
+       struct veth_net_stats __percpu *stats;
        struct veth_priv *priv;
 
        stats = alloc_percpu(struct veth_net_stats);
@@ -341,7 +325,7 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
 
 static struct rtnl_link_ops veth_link_ops;
 
-static int veth_newlink(struct net_device *dev,
+static int veth_newlink(struct net *src_net, struct net_device *dev,
                         struct nlattr *tb[], struct nlattr *data[])
 {
        int err;
@@ -349,18 +333,17 @@ static int veth_newlink(struct net_device *dev,
        struct veth_priv *priv;
        char ifname[IFNAMSIZ];
        struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+       struct ifinfomsg *ifmp;
+       struct net *net;
 
        /*
         * create and register peer first
-        *
-        * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
-        * skip it since no info from it is useful yet
         */
-
        if (data != NULL && data[VETH_INFO_PEER] != NULL) {
                struct nlattr *nla_peer;
 
                nla_peer = data[VETH_INFO_PEER];
+               ifmp = nla_data(nla_peer);
                err = nla_parse(peer_tb, IFLA_MAX,
                                nla_data(nla_peer) + sizeof(struct ifinfomsg),
                                nla_len(nla_peer) - sizeof(struct ifinfomsg),
@@ -373,27 +356,41 @@ static int veth_newlink(struct net_device *dev,
                        return err;
 
                tbp = peer_tb;
-       } else
+       } else {
+               ifmp = NULL;
                tbp = tb;
+       }
 
        if (tbp[IFLA_IFNAME])
                nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
        else
                snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
 
-       peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp);
-       if (IS_ERR(peer))
+       net = rtnl_link_get_net(src_net, tbp);
+       if (IS_ERR(net))
+               return PTR_ERR(net);
+
+       peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp);
+       if (IS_ERR(peer)) {
+               put_net(net);
                return PTR_ERR(peer);
+       }
 
        if (tbp[IFLA_ADDRESS] == NULL)
                random_ether_addr(peer->dev_addr);
 
        err = register_netdevice(peer);
+       put_net(net);
+       net = NULL;
        if (err < 0)
                goto err_register_peer;
 
        netif_carrier_off(peer);
 
+       err = rtnl_configure_link(peer, ifmp);
+       if (err < 0)
+               goto err_configure_peer;
+
        /*
         * register dev last
         *
@@ -435,6 +432,7 @@ static int veth_newlink(struct net_device *dev,
 err_register_dev:
        /* nothing to do */
 err_alloc_name:
+err_configure_peer:
        unregister_netdevice(peer);
        return err;
 
@@ -443,7 +441,7 @@ err_register_peer:
        return err;
 }
 
-static void veth_dellink(struct net_device *dev)
+static void veth_dellink(struct net_device *dev, struct list_head *head)
 {
        struct veth_priv *priv;
        struct net_device *peer;
@@ -451,8 +449,8 @@ static void veth_dellink(struct net_device *dev)
        priv = netdev_priv(dev);
        peer = priv->peer;
 
-       unregister_netdevice(dev);
-       unregister_netdevice(peer);
+       unregister_netdevice_queue(dev, head);
+       unregister_netdevice_queue(peer, head);
 }
 
 static const struct nla_policy veth_policy[VETH_INFO_MAX + 1];