mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	macvlan: add multicast filter
Setting up IPv6 addresses on configurations with many macvlans is not really working, as many multicast messages are dropped. Add a multicast filter to macvlan to reduce the amount of cloned skbs and overhead. Successfully tested with 1024 macvlans on one ethernet device. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Ben Greear <greearb@candelatech.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									6d1ccff627
								
							
						
					
					
						commit
						cd431e7385
					
				
					 2 changed files with 29 additions and 0 deletions
				
			
		| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
#include <linux/if_vlan.h>
 | 
					#include <linux/if_vlan.h>
 | 
				
			||||||
#include <linux/if_link.h>
 | 
					#include <linux/if_link.h>
 | 
				
			||||||
#include <linux/if_macvlan.h>
 | 
					#include <linux/if_macvlan.h>
 | 
				
			||||||
 | 
					#include <linux/hash.h>
 | 
				
			||||||
#include <net/rtnetlink.h>
 | 
					#include <net/rtnetlink.h>
 | 
				
			||||||
#include <net/xfrm.h>
 | 
					#include <net/xfrm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,6 +127,13 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
 | 
				
			||||||
	return vlan->receive(skb);
 | 
						return vlan->receive(skb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int mc_hash(const unsigned char *addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 val = __get_unaligned_cpu32(addr + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return hash_32(val, MACVLAN_MC_FILTER_BITS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void macvlan_broadcast(struct sk_buff *skb,
 | 
					static void macvlan_broadcast(struct sk_buff *skb,
 | 
				
			||||||
			      const struct macvlan_port *port,
 | 
								      const struct macvlan_port *port,
 | 
				
			||||||
			      struct net_device *src,
 | 
								      struct net_device *src,
 | 
				
			||||||
| 
						 | 
					@ -137,6 +145,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
 | 
				
			||||||
	struct sk_buff *nskb;
 | 
						struct sk_buff *nskb;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
						unsigned int hash = mc_hash(eth->h_dest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (skb->protocol == htons(ETH_P_PAUSE))
 | 
						if (skb->protocol == htons(ETH_P_PAUSE))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -146,6 +155,8 @@ static void macvlan_broadcast(struct sk_buff *skb,
 | 
				
			||||||
			if (vlan->dev == src || !(vlan->mode & mode))
 | 
								if (vlan->dev == src || !(vlan->mode & mode))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!test_bit(hash, vlan->mc_filter))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
			nskb = skb_clone(skb, GFP_ATOMIC);
 | 
								nskb = skb_clone(skb, GFP_ATOMIC);
 | 
				
			||||||
			err = macvlan_broadcast_one(nskb, vlan, eth,
 | 
								err = macvlan_broadcast_one(nskb, vlan, eth,
 | 
				
			||||||
					 mode == MACVLAN_MODE_BRIDGE);
 | 
										 mode == MACVLAN_MODE_BRIDGE);
 | 
				
			||||||
| 
						 | 
					@ -405,6 +416,18 @@ static void macvlan_set_mac_lists(struct net_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct macvlan_dev *vlan = netdev_priv(dev);
 | 
						struct macvlan_dev *vlan = netdev_priv(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
 | 
				
			||||||
 | 
							bitmap_fill(vlan->mc_filter, MACVLAN_MC_FILTER_SZ);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							struct netdev_hw_addr *ha;
 | 
				
			||||||
 | 
							DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bitmap_zero(filter, MACVLAN_MC_FILTER_SZ);
 | 
				
			||||||
 | 
							netdev_for_each_mc_addr(ha, dev) {
 | 
				
			||||||
 | 
								__set_bit(mc_hash(ha->addr), filter);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							bitmap_copy(vlan->mc_filter, filter, MACVLAN_MC_FILTER_SZ);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	dev_uc_sync(vlan->lowerdev, dev);
 | 
						dev_uc_sync(vlan->lowerdev, dev);
 | 
				
			||||||
	dev_mc_sync(vlan->lowerdev, dev);
 | 
						dev_mc_sync(vlan->lowerdev, dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,6 +52,9 @@ struct macvlan_pcpu_stats {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define MAX_MACVTAP_QUEUES	(NR_CPUS < 16 ? NR_CPUS : 16)
 | 
					#define MAX_MACVTAP_QUEUES	(NR_CPUS < 16 ? NR_CPUS : 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MACVLAN_MC_FILTER_BITS	8
 | 
				
			||||||
 | 
					#define MACVLAN_MC_FILTER_SZ	(1 << MACVLAN_MC_FILTER_BITS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct macvlan_dev {
 | 
					struct macvlan_dev {
 | 
				
			||||||
	struct net_device	*dev;
 | 
						struct net_device	*dev;
 | 
				
			||||||
	struct list_head	list;
 | 
						struct list_head	list;
 | 
				
			||||||
| 
						 | 
					@ -59,6 +62,9 @@ struct macvlan_dev {
 | 
				
			||||||
	struct macvlan_port	*port;
 | 
						struct macvlan_port	*port;
 | 
				
			||||||
	struct net_device	*lowerdev;
 | 
						struct net_device	*lowerdev;
 | 
				
			||||||
	struct macvlan_pcpu_stats __percpu *pcpu_stats;
 | 
						struct macvlan_pcpu_stats __percpu *pcpu_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum macvlan_mode	mode;
 | 
						enum macvlan_mode	mode;
 | 
				
			||||||
	u16			flags;
 | 
						u16			flags;
 | 
				
			||||||
	int (*receive)(struct sk_buff *skb);
 | 
						int (*receive)(struct sk_buff *skb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue