diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
| -rw-r--r-- | net/8021q/vlan_dev.c | 153 | 
1 files changed, 82 insertions, 71 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 09bf1c38805..dd11f612e03 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -61,32 +61,13 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)  		pr_debug("%s: unable to resolve type %X addresses\n",  			 dev->name, ntohs(veth->h_vlan_encapsulated_proto)); -		memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); +		ether_addr_copy(veth->h_source, dev->dev_addr);  		break;  	}  	return 0;  } -static inline u16 -vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb) -{ -	struct vlan_priority_tci_mapping *mp; - -	smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */ - -	mp = vlan_dev_priv(dev)->egress_priority_map[(skb->priority & 0xF)]; -	while (mp) { -		if (mp->priority == skb->priority) { -			return mp->vlan_qos; /* This should already be shifted -					      * to mask correctly with the -					      * VLAN's TCI */ -		} -		mp = mp->next; -	} -	return 0; -} -  /*   *	Create the VLAN header for an arbitrary protocol layer   * @@ -111,7 +92,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,  		vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);  		vlan_tci = vlan->vlan_id; -		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); +		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);  		vhdr->h_vlan_TCI = htons(vlan_tci);  		/* @@ -168,7 +149,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,  	    vlan->flags & VLAN_FLAG_REORDER_HDR) {  		u16 vlan_tci;  		vlan_tci = vlan->vlan_id; -		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); +		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);  		skb = __vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);  	} @@ -322,7 +303,7 @@ static int vlan_dev_open(struct net_device *dev)  			goto clear_allmulti;  	} -	memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); +	ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);  	if (vlan->flags & VLAN_FLAG_GVRP)  		vlan_gvrp_request_join(dev); @@ -386,7 +367,7 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)  		dev_uc_del(real_dev, dev->dev_addr);  out: -	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); +	ether_addr_copy(dev->dev_addr, addr->sa_data);  	return 0;  } @@ -543,12 +524,37 @@ static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass)  	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass);  } +static int vlan_dev_get_lock_subclass(struct net_device *dev) +{ +	return vlan_dev_priv(dev)->nest_level; +} +  static const struct header_ops vlan_header_ops = {  	.create	 = vlan_dev_hard_header,  	.rebuild = vlan_dev_rebuild_header,  	.parse	 = eth_header_parse,  }; +static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev, +				     unsigned short type, +				     const void *daddr, const void *saddr, +				     unsigned int len) +{ +	struct vlan_dev_priv *vlan = vlan_dev_priv(dev); +	struct net_device *real_dev = vlan->real_dev; + +	if (saddr == NULL) +		saddr = dev->dev_addr; + +	return dev_hard_header(skb, real_dev, type, daddr, saddr, len); +} + +static const struct header_ops vlan_passthru_header_ops = { +	.create	 = vlan_passthru_hard_header, +	.rebuild = dev_rebuild_header, +	.parse	 = eth_header_parse, +}; +  static struct device_type vlan_type = {  	.name	= "vlan",  }; @@ -558,7 +564,6 @@ static const struct net_device_ops vlan_netdev_ops;  static int vlan_dev_init(struct net_device *dev)  {  	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; -	int subclass = 0;  	netif_carrier_off(dev); @@ -577,6 +582,9 @@ static int vlan_dev_init(struct net_device *dev)  	dev->features |= real_dev->vlan_features | NETIF_F_LLTX;  	dev->gso_max_size = real_dev->gso_max_size; +	if (dev->features & NETIF_F_VLAN_FEATURES) +		netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n"); +  	/* ipv6 shared card related stuff */  	dev->dev_id = real_dev->dev_id; @@ -591,8 +599,9 @@ static int vlan_dev_init(struct net_device *dev)  #endif  	dev->needed_headroom = real_dev->needed_headroom; -	if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) { -		dev->header_ops      = real_dev->header_ops; +	if (vlan_hw_offload_capable(real_dev->features, +				    vlan_dev_priv(dev)->vlan_proto)) { +		dev->header_ops      = &vlan_passthru_header_ops;  		dev->hard_header_len = real_dev->hard_header_len;  	} else {  		dev->header_ops      = &vlan_header_ops; @@ -603,12 +612,9 @@ static int vlan_dev_init(struct net_device *dev)  	SET_NETDEV_DEVTYPE(dev, &vlan_type); -	if (is_vlan_dev(real_dev)) -		subclass = 1; - -	vlan_dev_set_lockdep_class(dev, subclass); +	vlan_dev_set_lockdep_class(dev, vlan_dev_get_lock_subclass(dev)); -	vlan_dev_priv(dev)->vlan_pcpu_stats = alloc_percpu(struct vlan_pcpu_stats); +	vlan_dev_priv(dev)->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);  	if (!vlan_dev_priv(dev)->vlan_pcpu_stats)  		return -ENOMEM; @@ -621,8 +627,6 @@ static void vlan_dev_uninit(struct net_device *dev)  	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);  	int i; -	free_percpu(vlan->vlan_pcpu_stats); -	vlan->vlan_pcpu_stats = NULL;  	for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {  		while ((pm = vlan->egress_priority_map[i]) != NULL) {  			vlan->egress_priority_map[i] = pm->next; @@ -637,9 +641,9 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev,  	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;  	netdev_features_t old_features = features; -	features &= real_dev->vlan_features; +	features = netdev_intersect_features(features, real_dev->vlan_features);  	features |= NETIF_F_RXCSUM; -	features &= real_dev->features; +	features = netdev_intersect_features(features, real_dev->features);  	features |= old_features & NETIF_F_SOFT_FEATURES;  	features |= NETIF_F_LLTX; @@ -665,38 +669,36 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev,  static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)  { +	struct vlan_pcpu_stats *p; +	u32 rx_errors = 0, tx_dropped = 0; +	int i; -	if (vlan_dev_priv(dev)->vlan_pcpu_stats) { -		struct vlan_pcpu_stats *p; -		u32 rx_errors = 0, tx_dropped = 0; -		int i; - -		for_each_possible_cpu(i) { -			u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; -			unsigned int start; - -			p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); -			do { -				start = u64_stats_fetch_begin_bh(&p->syncp); -				rxpackets	= p->rx_packets; -				rxbytes		= p->rx_bytes; -				rxmulticast	= p->rx_multicast; -				txpackets	= p->tx_packets; -				txbytes		= p->tx_bytes; -			} while (u64_stats_fetch_retry_bh(&p->syncp, start)); - -			stats->rx_packets	+= rxpackets; -			stats->rx_bytes		+= rxbytes; -			stats->multicast	+= rxmulticast; -			stats->tx_packets	+= txpackets; -			stats->tx_bytes		+= txbytes; -			/* rx_errors & tx_dropped are u32 */ -			rx_errors	+= p->rx_errors; -			tx_dropped	+= p->tx_dropped; -		} -		stats->rx_errors  = rx_errors; -		stats->tx_dropped = tx_dropped; +	for_each_possible_cpu(i) { +		u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; +		unsigned int start; + +		p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); +		do { +			start = u64_stats_fetch_begin_irq(&p->syncp); +			rxpackets	= p->rx_packets; +			rxbytes		= p->rx_bytes; +			rxmulticast	= p->rx_multicast; +			txpackets	= p->tx_packets; +			txbytes		= p->tx_bytes; +		} while (u64_stats_fetch_retry_irq(&p->syncp, start)); + +		stats->rx_packets	+= rxpackets; +		stats->rx_bytes		+= rxbytes; +		stats->multicast	+= rxmulticast; +		stats->tx_packets	+= txpackets; +		stats->tx_bytes		+= txbytes; +		/* rx_errors & tx_dropped are u32 */ +		rx_errors	+= p->rx_errors; +		tx_dropped	+= p->tx_dropped;  	} +	stats->rx_errors  = rx_errors; +	stats->tx_dropped = tx_dropped; +  	return stats;  } @@ -706,20 +708,19 @@ static void vlan_dev_poll_controller(struct net_device *dev)  	return;  } -static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo, -				  gfp_t gfp) +static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)  {  	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);  	struct net_device *real_dev = vlan->real_dev;  	struct netpoll *netpoll;  	int err = 0; -	netpoll = kzalloc(sizeof(*netpoll), gfp); +	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);  	err = -ENOMEM;  	if (!netpoll)  		goto out; -	err = __netpoll_setup(netpoll, real_dev, gfp); +	err = __netpoll_setup(netpoll, real_dev);  	if (err) {  		kfree(netpoll);  		goto out; @@ -779,8 +780,18 @@ static const struct net_device_ops vlan_netdev_ops = {  	.ndo_netpoll_cleanup	= vlan_dev_netpoll_cleanup,  #endif  	.ndo_fix_features	= vlan_dev_fix_features, +	.ndo_get_lock_subclass  = vlan_dev_get_lock_subclass,  }; +static void vlan_dev_free(struct net_device *dev) +{ +	struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + +	free_percpu(vlan->vlan_pcpu_stats); +	vlan->vlan_pcpu_stats = NULL; +	free_netdev(dev); +} +  void vlan_setup(struct net_device *dev)  {  	ether_setup(dev); @@ -790,7 +801,7 @@ void vlan_setup(struct net_device *dev)  	dev->tx_queue_len	= 0;  	dev->netdev_ops		= &vlan_netdev_ops; -	dev->destructor		= free_netdev; +	dev->destructor		= vlan_dev_free;  	dev->ethtool_ops	= &vlan_ethtool_ops;  	memset(dev->broadcast, 0, ETH_ALEN);  | 
