summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2016-05-31 23:45:44 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-01 20:48:46 -0400
commit9c127a016e66a85edaad6f9a674d0d1dce93d251 (patch)
treed8f23cacc9a57251677d1c862e893e3caf6bb6ca /drivers/net/macvlan.c
parent260916dfb48c374f7840f3b86e69afd3afdb6e96 (diff)
macvlan: Avoid unnecessary multicast cloning
Currently we always queue a multicast packet for further processing, even if none of the macvlan devices are subscribed to the address. This patch optimises this by adding a global multicast filter for a macvlan_port. Note that this patch doesn't handle the broadcast addresses of the individual macvlan devices correctly, if they are not all identical to vlan->lowerdev. However, this is already broken because there is no mechanism in place to update the individual multicast filters when you change the broadcast address. If someone cares enough they should fix this by collecting all broadcast addresses for a macvlan as we do for multicast and unicast. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index a71fa592b1fb..0c65bd914aed 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -49,6 +49,7 @@ struct macvlan_port {
49 bool passthru; 49 bool passthru;
50 int count; 50 int count;
51 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE]; 51 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE];
52 DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
52}; 53};
53 54
54struct macvlan_source_entry { 55struct macvlan_source_entry {
@@ -419,6 +420,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
419 420
420 port = macvlan_port_get_rcu(skb->dev); 421 port = macvlan_port_get_rcu(skb->dev);
421 if (is_multicast_ether_addr(eth->h_dest)) { 422 if (is_multicast_ether_addr(eth->h_dest)) {
423 unsigned int hash;
424
422 skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN); 425 skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);
423 if (!skb) 426 if (!skb)
424 return RX_HANDLER_CONSUMED; 427 return RX_HANDLER_CONSUMED;
@@ -436,7 +439,9 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
436 goto out; 439 goto out;
437 } 440 }
438 441
439 macvlan_broadcast_enqueue(port, src, skb); 442 hash = mc_hash(NULL, eth->h_dest);
443 if (test_bit(hash, port->mc_filter))
444 macvlan_broadcast_enqueue(port, src, skb);
440 445
441 return RX_HANDLER_PASS; 446 return RX_HANDLER_PASS;
442 } 447 }
@@ -722,12 +727,12 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
722 } 727 }
723} 728}
724 729
725static void macvlan_set_mac_lists(struct net_device *dev) 730static void macvlan_compute_filter(unsigned long *mc_filter,
731 struct net_device *dev,
732 struct macvlan_dev *vlan)
726{ 733{
727 struct macvlan_dev *vlan = netdev_priv(dev);
728
729 if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { 734 if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
730 bitmap_fill(vlan->mc_filter, MACVLAN_MC_FILTER_SZ); 735 bitmap_fill(mc_filter, MACVLAN_MC_FILTER_SZ);
731 } else { 736 } else {
732 struct netdev_hw_addr *ha; 737 struct netdev_hw_addr *ha;
733 DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ); 738 DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ);
@@ -739,10 +744,33 @@ static void macvlan_set_mac_lists(struct net_device *dev)
739 744
740 __set_bit(mc_hash(vlan, dev->broadcast), filter); 745 __set_bit(mc_hash(vlan, dev->broadcast), filter);
741 746
742 bitmap_copy(vlan->mc_filter, filter, MACVLAN_MC_FILTER_SZ); 747 bitmap_copy(mc_filter, filter, MACVLAN_MC_FILTER_SZ);
743 } 748 }
749}
750
751static void macvlan_set_mac_lists(struct net_device *dev)
752{
753 struct macvlan_dev *vlan = netdev_priv(dev);
754
755 macvlan_compute_filter(vlan->mc_filter, dev, vlan);
756
744 dev_uc_sync(vlan->lowerdev, dev); 757 dev_uc_sync(vlan->lowerdev, dev);
745 dev_mc_sync(vlan->lowerdev, dev); 758 dev_mc_sync(vlan->lowerdev, dev);
759
760 /* This is slightly inaccurate as we're including the subscription
761 * list of vlan->lowerdev too.
762 *
763 * Bug alert: This only works if everyone has the same broadcast
764 * address as lowerdev. As soon as someone changes theirs this
765 * will break.
766 *
767 * However, this is already broken as when you change your broadcast
768 * address we don't get called.
769 *
770 * The solution is to maintain a list of broadcast addresses like
771 * we do for uc/mc, if you care.
772 */
773 macvlan_compute_filter(vlan->port->mc_filter, vlan->lowerdev, NULL);
746} 774}
747 775
748static int macvlan_change_mtu(struct net_device *dev, int new_mtu) 776static int macvlan_change_mtu(struct net_device *dev, int new_mtu)