Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / drivers / net / macvlan.c
index b0e2865a6810782e115d61287ed23578646a855e..a665e902b9891096d76a427c1de26a61d49e3b3b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/if_link.h>
 #include <linux/if_macvlan.h>
 #include <linux/hash.h>
+#include <linux/workqueue.h>
 #include <net/rtnetlink.h>
 #include <net/xfrm.h>
 
@@ -40,10 +41,19 @@ struct macvlan_port {
        struct hlist_head       vlan_hash[MACVLAN_HASH_SIZE];
        struct list_head        vlans;
        struct rcu_head         rcu;
+       struct sk_buff_head     bc_queue;
+       struct work_struct      bc_work;
        bool                    passthru;
-       int                     count;
 };
 
+#define MACVLAN_PORT_IS_EMPTY(port)    list_empty(&port->vlans)
+
+struct macvlan_skb_cb {
+       const struct macvlan_dev *src;
+};
+
+#define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0]))
+
 static void macvlan_port_destroy(struct net_device *dev);
 
 static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
@@ -120,7 +130,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
        struct net_device *dev = vlan->dev;
 
        if (local)
-               return dev_forward_skb(dev, skb);
+               return __dev_forward_skb(dev, skb);
 
        skb->dev = dev;
        if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
@@ -128,7 +138,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
        else
                skb->pkt_type = PACKET_MULTICAST;
 
-       return netif_rx(skb);
+       return 0;
 }
 
 static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
@@ -175,32 +185,32 @@ static void macvlan_broadcast(struct sk_buff *skb,
                        if (likely(nskb))
                                err = macvlan_broadcast_one(
                                        nskb, vlan, eth,
-                                       mode == MACVLAN_MODE_BRIDGE);
+                                       mode == MACVLAN_MODE_BRIDGE) ?:
+                                     netif_rx_ni(nskb);
                        macvlan_count_rx(vlan, skb->len + ETH_HLEN,
                                         err == NET_RX_SUCCESS, 1);
                }
        }
 }
 
-/* called under rcu_read_lock() from netif_receive_skb */
-static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
+static void macvlan_process_broadcast(struct work_struct *w)
 {
-       struct macvlan_port *port;
-       struct sk_buff *skb = *pskb;
-       const struct ethhdr *eth = eth_hdr(skb);
-       const struct macvlan_dev *vlan;
-       const struct macvlan_dev *src;
-       struct net_device *dev;
-       unsigned int len = 0;
-       int ret = NET_RX_DROP;
+       struct macvlan_port *port = container_of(w, struct macvlan_port,
+                                                bc_work);
+       struct sk_buff *skb;
+       struct sk_buff_head list;
+
+       skb_queue_head_init(&list);
+
+       spin_lock_bh(&port->bc_queue.lock);
+       skb_queue_splice_tail_init(&port->bc_queue, &list);
+       spin_unlock_bh(&port->bc_queue.lock);
+
+       while ((skb = __skb_dequeue(&list))) {
+               const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src;
+
+               rcu_read_lock();
 
-       port = macvlan_port_get_rcu(skb->dev);
-       if (is_multicast_ether_addr(eth->h_dest)) {
-               skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
-               if (!skb)
-                       return RX_HANDLER_CONSUMED;
-               eth = eth_hdr(skb);
-               src = macvlan_hash_lookup(port, eth->h_source);
                if (!src)
                        /* frame comes from an external address */
                        macvlan_broadcast(skb, port, NULL,
@@ -213,20 +223,80 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
                        macvlan_broadcast(skb, port, src->dev,
                                          MACVLAN_MODE_VEPA |
                                          MACVLAN_MODE_BRIDGE);
-               else if (src->mode == MACVLAN_MODE_BRIDGE)
+               else
                        /*
                         * flood only to VEPA ports, bridge ports
                         * already saw the frame on the way out.
                         */
                        macvlan_broadcast(skb, port, src->dev,
                                          MACVLAN_MODE_VEPA);
-               else {
+
+               rcu_read_unlock();
+
+               kfree_skb(skb);
+       }
+}
+
+static void macvlan_broadcast_enqueue(struct macvlan_port *port,
+                                     struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+       int err = -ENOMEM;
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               goto err;
+
+       spin_lock(&port->bc_queue.lock);
+       if (skb_queue_len(&port->bc_queue) < skb->dev->tx_queue_len) {
+               __skb_queue_tail(&port->bc_queue, nskb);
+               err = 0;
+       }
+       spin_unlock(&port->bc_queue.lock);
+
+       if (err)
+               goto free_nskb;
+
+       schedule_work(&port->bc_work);
+       return;
+
+free_nskb:
+       kfree_skb(nskb);
+err:
+       atomic_long_inc(&skb->dev->rx_dropped);
+}
+
+/* called under rcu_read_lock() from netif_receive_skb */
+static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
+{
+       struct macvlan_port *port;
+       struct sk_buff *skb = *pskb;
+       const struct ethhdr *eth = eth_hdr(skb);
+       const struct macvlan_dev *vlan;
+       const struct macvlan_dev *src;
+       struct net_device *dev;
+       unsigned int len = 0;
+       int ret = NET_RX_DROP;
+
+       port = macvlan_port_get_rcu(skb->dev);
+       if (is_multicast_ether_addr(eth->h_dest)) {
+               skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
+               if (!skb)
+                       return RX_HANDLER_CONSUMED;
+               eth = eth_hdr(skb);
+               src = macvlan_hash_lookup(port, eth->h_source);
+               if (src && src->mode != MACVLAN_MODE_VEPA &&
+                   src->mode != MACVLAN_MODE_BRIDGE) {
                        /* forward to original port. */
                        vlan = src;
-                       ret = macvlan_broadcast_one(skb, vlan, eth, 0);
+                       ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?:
+                             netif_rx(skb);
                        goto out;
                }
 
+               MACVLAN_SKB_CB(skb)->src = src;
+               macvlan_broadcast_enqueue(port, skb);
+
                return RX_HANDLER_PASS;
        }
 
@@ -458,8 +528,10 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
        struct macvlan_dev *vlan = netdev_priv(dev);
        struct net_device *lowerdev = vlan->lowerdev;
 
-       if (change & IFF_ALLMULTI)
-               dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+       if (dev->flags & IFF_UP) {
+               if (change & IFF_ALLMULTI)
+                       dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+       }
 }
 
 static void macvlan_set_mac_lists(struct net_device *dev)
@@ -515,6 +587,11 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
 #define MACVLAN_STATE_MASK \
        ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
 
+static int macvlan_get_nest_level(struct net_device *dev)
+{
+       return ((struct macvlan_dev *)netdev_priv(dev))->nest_level;
+}
+
 static void macvlan_set_lockdep_class_one(struct net_device *dev,
                                          struct netdev_queue *txq,
                                          void *_unused)
@@ -525,8 +602,9 @@ static void macvlan_set_lockdep_class_one(struct net_device *dev,
 
 static void macvlan_set_lockdep_class(struct net_device *dev)
 {
-       lockdep_set_class(&dev->addr_list_lock,
-                         &macvlan_netdev_addr_lock_key);
+       lockdep_set_class_and_subclass(&dev->addr_list_lock,
+                                      &macvlan_netdev_addr_lock_key,
+                                      macvlan_get_nest_level(dev));
        netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL);
 }
 
@@ -559,8 +637,7 @@ static void macvlan_uninit(struct net_device *dev)
 
        free_percpu(vlan->pcpu_stats);
 
-       port->count -= 1;
-       if (!port->count)
+       if (MACVLAN_PORT_IS_EMPTY(port))
                macvlan_port_destroy(port->dev);
 }
 
@@ -721,6 +798,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
        .ndo_fdb_add            = macvlan_fdb_add,
        .ndo_fdb_del            = macvlan_fdb_del,
        .ndo_fdb_dump           = ndo_dflt_fdb_dump,
+       .ndo_get_lock_subclass  = macvlan_get_nest_level,
 };
 
 void macvlan_common_setup(struct net_device *dev)
@@ -761,6 +839,9 @@ static int macvlan_port_create(struct net_device *dev)
        for (i = 0; i < MACVLAN_HASH_SIZE; i++)
                INIT_HLIST_HEAD(&port->vlan_hash[i]);
 
+       skb_queue_head_init(&port->bc_queue);
+       INIT_WORK(&port->bc_work, macvlan_process_broadcast);
+
        err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
        if (err)
                kfree(port);
@@ -773,6 +854,7 @@ static void macvlan_port_destroy(struct net_device *dev)
 {
        struct macvlan_port *port = macvlan_port_get_rtnl(dev);
 
+       cancel_work_sync(&port->bc_work);
        dev->priv_flags &= ~IFF_MACVLAN_PORT;
        netdev_rx_handler_unregister(dev);
        kfree_rcu(port, rcu);
@@ -849,6 +931,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
        vlan->dev      = dev;
        vlan->port     = port;
        vlan->set_features = MACVLAN_FEATURES;
+       vlan->nest_level = dev_get_nest_level(lowerdev, netif_is_macvlan) + 1;
 
        vlan->mode     = MACVLAN_MODE_VEPA;
        if (data && data[IFLA_MACVLAN_MODE])
@@ -858,13 +941,12 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
                vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
 
        if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
-               if (port->count)
+               if (!MACVLAN_PORT_IS_EMPTY(port))
                        return -EINVAL;
                port->passthru = true;
                eth_hw_addr_inherit(dev, lowerdev);
        }
 
-       port->count += 1;
        err = register_netdevice(dev);
        if (err < 0)
                goto destroy_port;
@@ -882,8 +964,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 unregister_netdev:
        unregister_netdevice(dev);
 destroy_port:
-       port->count -= 1;
-       if (!port->count)
+       if (MACVLAN_PORT_IS_EMPTY(port))
                macvlan_port_destroy(lowerdev);
 
        return err;
@@ -1018,6 +1099,13 @@ static int macvlan_device_event(struct notifier_block *unused,
                        netdev_update_features(vlan->dev);
                }
                break;
+       case NETDEV_CHANGEMTU:
+               list_for_each_entry(vlan, &port->vlans, list) {
+                       if (vlan->dev->mtu <= dev->mtu)
+                               continue;
+                       dev_set_mtu(vlan->dev, dev->mtu);
+               }
+               break;
        case NETDEV_UNREGISTER:
                /* twiddle thumbs on netns device moves */
                if (dev->reg_state != NETREG_UNREGISTERING)