1961 lines · 50.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) 2007 Patrick McHardy <kaber@trash.net> * * The code this is based on carried the following copyright notice: * --- * (C) Copyright 2001-2006 * Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com * Re-worked by Ben Greear <greearb@candelatech.com> * --- */#include <linux/kernel.h>#include <linux/types.h>#include <linux/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/rculist.h>#include <linux/notifier.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/net_tstamp.h>#include <linux/ethtool.h>#include <linux/if_arp.h>#include <linux/if_vlan.h>#include <linux/if_link.h>#include <linux/if_macvlan.h>#include <linux/hash.h>#include <linux/workqueue.h>#include <net/netdev_lock.h>#include <net/rtnetlink.h>#include <net/xfrm.h>#include <linux/netpoll.h>#include <linux/phy.h> #define MACVLAN_HASH_BITS	8#define MACVLAN_HASH_SIZE	(1<<MACVLAN_HASH_BITS)#define MACVLAN_DEFAULT_BC_QUEUE_LEN	1000 #define MACVLAN_F_PASSTHRU	1#define MACVLAN_F_ADDRCHANGE	2 struct macvlan_port {	struct net_device	*dev;	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];	struct list_head	vlans;	struct sk_buff_head	bc_queue;	struct work_struct	bc_work;	u32			bc_queue_len_used;	int			bc_cutoff;	u32			flags;	int			count;	struct hlist_head	vlan_source_hash[MACVLAN_HASH_SIZE];	DECLARE_BITMAP(bc_filter, MACVLAN_MC_FILTER_SZ);	DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);	unsigned char           perm_addr[ETH_ALEN];}; struct macvlan_source_entry {	struct hlist_node	hlist;	struct macvlan_dev __rcu *vlan;	unsigned char		addr[6+2] __aligned(sizeof(u16));	struct rcu_head		rcu;}; 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 void update_port_bc_queue_len(struct macvlan_port *port); static inline bool macvlan_passthru(const struct macvlan_port *port){	return port->flags & MACVLAN_F_PASSTHRU;} static inline void macvlan_set_passthru(struct macvlan_port *port){	port->flags |= MACVLAN_F_PASSTHRU;} static inline bool macvlan_addr_change(const struct macvlan_port *port){	return port->flags & MACVLAN_F_ADDRCHANGE;} static inline void macvlan_set_addr_change(struct macvlan_port *port){	port->flags |= MACVLAN_F_ADDRCHANGE;} static inline void macvlan_clear_addr_change(struct macvlan_port *port){	port->flags &= ~MACVLAN_F_ADDRCHANGE;} /* Hash Ethernet address */static u32 macvlan_eth_hash(const unsigned char *addr){	u64 value = get_unaligned((u64 *)addr); 	/* only want 6 bytes */#ifdef __BIG_ENDIAN	value >>= 16;#else	value <<= 16;#endif	return hash_64(value, MACVLAN_HASH_BITS);} static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev){	return rcu_dereference(dev->rx_handler_data);} static struct macvlan_port *macvlan_port_get_rtnl(const struct net_device *dev){	return rtnl_dereference(dev->rx_handler_data);} static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,					       const unsigned char *addr){	struct macvlan_dev *vlan;	u32 idx = macvlan_eth_hash(addr); 	hlist_for_each_entry_rcu(vlan, &port->vlan_hash[idx], hlist,				 lockdep_rtnl_is_held()) {		if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr))			return vlan;	}	return NULL;} static struct macvlan_source_entry *macvlan_hash_lookup_source(	const struct macvlan_dev *vlan,	const unsigned char *addr){	struct macvlan_source_entry *entry;	u32 idx = macvlan_eth_hash(addr);	struct hlist_head *h = &vlan->port->vlan_source_hash[idx]; 	hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {		if (ether_addr_equal_64bits(entry->addr, addr) &&		    rcu_access_pointer(entry->vlan) == vlan)			return entry;	}	return NULL;} static int macvlan_hash_add_source(struct macvlan_dev *vlan,				   const unsigned char *addr){	struct macvlan_port *port = vlan->port;	struct macvlan_source_entry *entry;	struct hlist_head *h; 	entry = macvlan_hash_lookup_source(vlan, addr);	if (entry)		return 0; 	entry = kmalloc_obj(*entry);	if (!entry)		return -ENOMEM; 	ether_addr_copy(entry->addr, addr);	RCU_INIT_POINTER(entry->vlan, vlan);	h = &port->vlan_source_hash[macvlan_eth_hash(addr)];	hlist_add_head_rcu(&entry->hlist, h);	WRITE_ONCE(vlan->macaddr_count, vlan->macaddr_count + 1); 	return 0;} static void macvlan_hash_add(struct macvlan_dev *vlan){	struct macvlan_port *port = vlan->port;	const unsigned char *addr = vlan->dev->dev_addr;	u32 idx = macvlan_eth_hash(addr); 	hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[idx]);} static void macvlan_hash_del_source(struct macvlan_source_entry *entry){	RCU_INIT_POINTER(entry->vlan, NULL);	hlist_del_rcu(&entry->hlist);	kfree_rcu(entry, rcu);} static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync){	hlist_del_rcu(&vlan->hlist);	if (sync)		synchronize_rcu();} static void macvlan_hash_change_addr(struct macvlan_dev *vlan,					const unsigned char *addr){	macvlan_hash_del(vlan, true);	/* Now that we are unhashed it is safe to change the device	 * address without confusing packet delivery.	 */	eth_hw_addr_set(vlan->dev, addr);	macvlan_hash_add(vlan);} static bool macvlan_addr_busy(const struct macvlan_port *port,			      const unsigned char *addr){	/* Test to see if the specified address is	 * currently in use by the underlying device or	 * another macvlan.	 */	if (!macvlan_passthru(port) && !macvlan_addr_change(port) &&	    ether_addr_equal_64bits(port->dev->dev_addr, addr))		return true; 	if (macvlan_hash_lookup(port, addr))		return true; 	return false;}  static int macvlan_broadcast_one(struct sk_buff *skb,				 const struct macvlan_dev *vlan,				 const struct ethhdr *eth, bool local){	struct net_device *dev = vlan->dev; 	if (local)		return __dev_forward_skb(dev, skb); 	skb->dev = dev;	if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))		skb->pkt_type = PACKET_BROADCAST;	else		skb->pkt_type = PACKET_MULTICAST; 	return 0;} static u32 macvlan_hash_mix(const struct macvlan_dev *vlan){	return (u32)(((unsigned long)vlan) >> L1_CACHE_SHIFT);}  static unsigned int mc_hash(const struct macvlan_dev *vlan,			    const unsigned char *addr){	u32 val = get_unaligned((u32 *)(addr + 2)); 	val ^= macvlan_hash_mix(vlan);	return hash_32(val, MACVLAN_MC_FILTER_BITS);} static void macvlan_broadcast(struct sk_buff *skb,			      const struct macvlan_port *port,			      struct net_device *src,			      enum macvlan_mode mode){	const struct ethhdr *eth = eth_hdr(skb);	const struct macvlan_dev *vlan;	struct sk_buff *nskb;	unsigned int i;	int err;	unsigned int hash; 	if (skb->protocol == htons(ETH_P_PAUSE))		return; 	hash_for_each_rcu(port->vlan_hash, i, vlan, hlist) {		if (vlan->dev == src || !(READ_ONCE(vlan->mode) & mode))			continue; 		hash = mc_hash(vlan, eth->h_dest);		if (!test_bit(hash, vlan->mc_filter))			continue; 		err = NET_RX_DROP;		nskb = skb_clone(skb, GFP_ATOMIC);		if (likely(nskb))			err = macvlan_broadcast_one(nskb, vlan, eth,					mode == MACVLAN_MODE_BRIDGE) ?:			      netif_rx(nskb);		macvlan_count_rx(vlan, skb->len + ETH_HLEN,				 err == NET_RX_SUCCESS, true);	}} static void macvlan_multicast_rx(const struct macvlan_port *port,				 const struct macvlan_dev *src,				 struct sk_buff *skb){	if (!src)		/* frame comes from an external address */		macvlan_broadcast(skb, port, NULL,				  MACVLAN_MODE_PRIVATE |				  MACVLAN_MODE_VEPA    |				  MACVLAN_MODE_PASSTHRU|				  MACVLAN_MODE_BRIDGE);	else if (READ_ONCE(src->mode) == MACVLAN_MODE_VEPA)		/* flood to everyone except source */		macvlan_broadcast(skb, port, src->dev,				  MACVLAN_MODE_VEPA |				  MACVLAN_MODE_BRIDGE);	else		/*		 * Flood to VEPA and bridge ports. We cannot distinguish		 * a looped-back locally-originated multicast from one		 * sent by an external source sharing the same source MAC		 * (e.g., VRRP virtual MAC), so deliver to bridge ports		 * as well to ensure correct reception in all cases.		 */		macvlan_broadcast(skb, port, NULL,				  MACVLAN_MODE_VEPA |				  MACVLAN_MODE_BRIDGE);} static void macvlan_process_broadcast(struct work_struct *w){	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();		macvlan_multicast_rx(port, src, skb);		rcu_read_unlock(); 		if (src)			dev_put(src->dev);		consume_skb(skb); 		cond_resched();	}} static void macvlan_broadcast_enqueue(struct macvlan_port *port,				      const struct macvlan_dev *src,				      struct sk_buff *skb){	u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used);	struct sk_buff *nskb;	int err = -ENOMEM; 	if (skb_queue_len_lockless(&port->bc_queue) >= bc_queue_len_used)		goto err; 	nskb = skb_clone(skb, GFP_ATOMIC);	if (!nskb)		goto err; 	MACVLAN_SKB_CB(nskb)->src = src; 	spin_lock(&port->bc_queue.lock);	if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) {		if (src)			dev_hold(src->dev);		__skb_queue_tail(&port->bc_queue, nskb);		err = 0;	}	spin_unlock(&port->bc_queue.lock); 	queue_work(system_dfl_wq, &port->bc_work); 	if (err)		goto free_nskb; 	return; free_nskb:	kfree_skb_reason(nskb, SKB_DROP_REASON_MACVLAN_BROADCAST_BACKLOG);err:	dev_core_stats_rx_dropped_inc(skb->dev);} static void macvlan_flush_sources(struct macvlan_port *port,				  struct macvlan_dev *vlan){	struct macvlan_source_entry *entry;	struct hlist_node *next;	int i; 	hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist)		if (rcu_access_pointer(entry->vlan) == vlan)			macvlan_hash_del_source(entry); 	WRITE_ONCE(vlan->macaddr_count, 0);} static void macvlan_forward_source_one(struct sk_buff *skb,				       struct macvlan_dev *vlan){	struct sk_buff *nskb;	struct net_device *dev;	int len;	int ret; 	dev = vlan->dev;	if (unlikely(!(dev->flags & IFF_UP)))		return; 	nskb = skb_clone(skb, GFP_ATOMIC);	if (!nskb)		return; 	len = nskb->len + ETH_HLEN;	nskb->dev = dev; 	if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, dev->dev_addr))		nskb->pkt_type = PACKET_HOST; 	ret = __netif_rx(nskb);	macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);} static bool macvlan_forward_source(struct sk_buff *skb,				   struct macvlan_port *port,				   const unsigned char *addr){	struct macvlan_source_entry *entry;	u32 idx = macvlan_eth_hash(addr);	struct hlist_head *h = &port->vlan_source_hash[idx];	bool consume = false; 	hlist_for_each_entry_rcu(entry, h, hlist) {		if (ether_addr_equal_64bits(entry->addr, addr)) {			struct macvlan_dev *vlan = rcu_dereference(entry->vlan); 			if (!vlan)				continue; 			if (READ_ONCE(vlan->flags) & MACVLAN_FLAG_NODST)				consume = true;			macvlan_forward_source_one(skb, vlan);		}	} 	return consume;} /* 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;	rx_handler_result_t handle_res; 	/* Packets from dev_loopback_xmit() do not have L2 header, bail out */	if (unlikely(skb->pkt_type == PACKET_LOOPBACK))		return RX_HANDLER_PASS; 	port = macvlan_port_get_rcu(skb->dev);	if (is_multicast_ether_addr(eth->h_dest)) {		unsigned int hash; 		skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);		if (!skb)			return RX_HANDLER_CONSUMED;		*pskb = skb;		eth = eth_hdr(skb);		if (macvlan_forward_source(skb, port, eth->h_source)) {			kfree_skb(skb);			return RX_HANDLER_CONSUMED;		}		src = macvlan_hash_lookup(port, eth->h_source);		if (src) {			enum macvlan_mode mode = READ_ONCE(src->mode); 			if (mode != MACVLAN_MODE_VEPA &&			    mode != MACVLAN_MODE_BRIDGE) {				/* forward to original port. */				vlan = src;				ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?:				      __netif_rx(skb);				handle_res = RX_HANDLER_CONSUMED;				goto out;

Lines 1–500 of 1961.