X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fnet%2Fmacvlan.c;h=d6aeaa5f25eaa86df9780d03783b548631e92262;hb=249ddc79a38a8918ad53ac22606ca8af694344a5;hp=3ad5425b82ddcccd8a58dcef731d5d7451ac0dcb;hpb=cfef6047c4027a8448ec8dafeaf2bb362cc882e4;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 3ad5425b82dd..d6aeaa5f25ea 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -70,16 +70,17 @@ static void macvlan_hash_add(struct macvlan_dev *vlan) hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]); } -static void macvlan_hash_del(struct macvlan_dev *vlan) +static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) { hlist_del_rcu(&vlan->hlist); - synchronize_rcu(); + if (sync) + synchronize_rcu(); } static void macvlan_hash_change_addr(struct macvlan_dev *vlan, const unsigned char *addr) { - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, true); /* Now that we are unhashed it is safe to change the device * address without confusing packet delivery. */ @@ -237,10 +238,8 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) dest = macvlan_hash_lookup(port, eth->h_dest); if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { - unsigned int length = skb->len + ETH_HLEN; - int ret = dest->forward(dest->dev, skb); - macvlan_count_rx(dest, length, - ret == NET_RX_SUCCESS, 0); + /* send to lowerdev first for its network taps */ + vlan->forward(vlan->lowerdev, skb); return NET_XMIT_SUCCESS; } @@ -345,7 +344,7 @@ static int macvlan_stop(struct net_device *dev) dev_uc_del(lowerdev, dev->dev_addr); hash_del: - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, !dev->dismantle); return 0; } @@ -584,26 +583,18 @@ static int macvlan_port_create(struct net_device *dev) err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); if (err) kfree(port); - - dev->priv_flags |= IFF_MACVLAN_PORT; + else + dev->priv_flags |= IFF_MACVLAN_PORT; return err; } -static void macvlan_port_rcu_free(struct rcu_head *head) -{ - struct macvlan_port *port; - - port = container_of(head, struct macvlan_port, rcu); - kfree(port); -} - static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get(dev); dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); - call_rcu(&port->rcu, macvlan_port_rcu_free); + kfree_rcu(port, rcu); } static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -785,6 +776,7 @@ static int macvlan_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct macvlan_dev *vlan, *next; struct macvlan_port *port; + LIST_HEAD(list_kill); if (!macvlan_port_exists(dev)) return NOTIFY_DONE; @@ -810,7 +802,9 @@ static int macvlan_device_event(struct notifier_block *unused, break; list_for_each_entry_safe(vlan, next, &port->vlans, list) - vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); + vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill); + unregister_netdevice_many(&list_kill); + list_del(&list_kill); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */