diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 187 | 
1 files changed, 111 insertions, 76 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index b624fe4d9bd..d94537914a7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -948,7 +948,7 @@ int dev_alloc_name(struct net_device *dev, const char *name)  }  EXPORT_SYMBOL(dev_alloc_name); -static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt) +static int dev_get_valid_name(struct net_device *dev, const char *name)  {  	struct net *net; @@ -958,7 +958,7 @@ static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt  	if (!dev_valid_name(name))  		return -EINVAL; -	if (fmt && strchr(name, '%')) +	if (strchr(name, '%'))  		return dev_alloc_name(dev, name);  	else if (__dev_get_by_name(net, name))  		return -EEXIST; @@ -995,7 +995,7 @@ int dev_change_name(struct net_device *dev, const char *newname)  	memcpy(oldname, dev->name, IFNAMSIZ); -	err = dev_get_valid_name(dev, newname, 1); +	err = dev_get_valid_name(dev, newname);  	if (err < 0)  		return err; @@ -1007,7 +1007,7 @@ rollback:  	}  	write_lock_bh(&dev_base_lock); -	hlist_del(&dev->name_hlist); +	hlist_del_rcu(&dev->name_hlist);  	write_unlock_bh(&dev_base_lock);  	synchronize_rcu(); @@ -1317,7 +1317,8 @@ void dev_disable_lro(struct net_device *dev)  		return;  	__ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO); -	WARN_ON(dev->features & NETIF_F_LRO); +	if (unlikely(dev->features & NETIF_F_LRO)) +		netdev_WARN(dev, "failed to disable LRO!\n");  }  EXPORT_SYMBOL(dev_disable_lro); @@ -2504,8 +2505,8 @@ static inline void ____napi_schedule(struct softnet_data *sd,  __u32 __skb_get_rxhash(struct sk_buff *skb)  {  	int nhoff, hash = 0, poff; -	struct ipv6hdr *ip6; -	struct iphdr *ip; +	const struct ipv6hdr *ip6; +	const struct iphdr *ip;  	u8 ip_proto;  	u32 addr1, addr2, ihl;  	union { @@ -2520,7 +2521,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)  		if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))  			goto done; -		ip = (struct iphdr *) (skb->data + nhoff); +		ip = (const struct iphdr *) (skb->data + nhoff);  		if (ip->frag_off & htons(IP_MF | IP_OFFSET))  			ip_proto = 0;  		else @@ -2533,7 +2534,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)  		if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))  			goto done; -		ip6 = (struct ipv6hdr *) (skb->data + nhoff); +		ip6 = (const struct ipv6hdr *) (skb->data + nhoff);  		ip_proto = ip6->nexthdr;  		addr1 = (__force u32) ip6->saddr.s6_addr32[3];  		addr2 = (__force u32) ip6->daddr.s6_addr32[3]; @@ -3078,25 +3079,6 @@ void netdev_rx_handler_unregister(struct net_device *dev)  }  EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); -static void vlan_on_bond_hook(struct sk_buff *skb) -{ -	/* -	 * Make sure ARP frames received on VLAN interfaces stacked on -	 * bonding interfaces still make their way to any base bonding -	 * device that may have registered for a specific ptype. -	 */ -	if (skb->dev->priv_flags & IFF_802_1Q_VLAN && -	    vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING && -	    skb->protocol == htons(ETH_P_ARP)) { -		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - -		if (!skb2) -			return; -		skb2->dev = vlan_dev_real_dev(skb->dev); -		netif_rx(skb2); -	} -} -  static int __netif_receive_skb(struct sk_buff *skb)  {  	struct packet_type *ptype, *pt_prev; @@ -3132,6 +3114,12 @@ another_round:  	__this_cpu_inc(softnet_data.processed); +	if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { +		skb = vlan_untag(skb); +		if (unlikely(!skb)) +			goto out; +	} +  #ifdef CONFIG_NET_CLS_ACT  	if (skb->tc_verd & TC_NCLS) {  		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); @@ -3179,15 +3167,13 @@ ncls:  			ret = deliver_skb(skb, pt_prev, orig_dev);  			pt_prev = NULL;  		} -		if (vlan_hwaccel_do_receive(&skb)) { +		if (vlan_do_receive(&skb)) {  			ret = __netif_receive_skb(skb);  			goto out;  		} else if (unlikely(!skb))  			goto out;  	} -	vlan_on_bond_hook(skb); -  	/* deliver only exact match when indicated */  	null_or_dev = deliver_exact ? skb->dev : NULL; @@ -4512,6 +4498,30 @@ void dev_set_rx_mode(struct net_device *dev)  }  /** + *	dev_ethtool_get_settings - call device's ethtool_ops::get_settings() + *	@dev: device + *	@cmd: memory area for ethtool_ops::get_settings() result + * + *      The cmd arg is initialized properly (cleared and + *      ethtool_cmd::cmd field set to ETHTOOL_GSET). + * + *	Return device's ethtool_ops::get_settings() result value or + *	-EOPNOTSUPP when device doesn't expose + *	ethtool_ops::get_settings() operation. + */ +int dev_ethtool_get_settings(struct net_device *dev, +			     struct ethtool_cmd *cmd) +{ +	if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) +		return -EOPNOTSUPP; + +	memset(cmd, 0, sizeof(struct ethtool_cmd)); +	cmd->cmd = ETHTOOL_GSET; +	return dev->ethtool_ops->get_settings(dev, cmd); +} +EXPORT_SYMBOL(dev_ethtool_get_settings); + +/**   *	dev_get_flags - get flags reported to userspace   *	@dev: device   * @@ -5116,7 +5126,7 @@ static void rollback_registered_many(struct list_head *head)  			list_del(&dev->unreg_list);  			continue;  		} - +		dev->dismantle = true;  		BUG_ON(dev->reg_state != NETREG_REGISTERED);  	} @@ -5242,11 +5252,13 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)  }  EXPORT_SYMBOL(netdev_fix_features); -void netdev_update_features(struct net_device *dev) +int __netdev_update_features(struct net_device *dev)  {  	u32 features;  	int err = 0; +	ASSERT_RTNL(); +  	features = netdev_get_wanted_features(dev);  	if (dev->netdev_ops->ndo_fix_features) @@ -5256,24 +5268,60 @@ void netdev_update_features(struct net_device *dev)  	features = netdev_fix_features(dev, features);  	if (dev->features == features) -		return; +		return 0; -	netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n", +	netdev_dbg(dev, "Features changed: 0x%08x -> 0x%08x\n",  		dev->features, features);  	if (dev->netdev_ops->ndo_set_features)  		err = dev->netdev_ops->ndo_set_features(dev, features); -	if (!err) -		dev->features = features; -	else if (err < 0) +	if (unlikely(err < 0)) {  		netdev_err(dev,  			"set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",  			err, features, dev->features); +		return -1; +	} + +	if (!err) +		dev->features = features; + +	return 1; +} + +/** + *	netdev_update_features - recalculate device features + *	@dev: the device to check + * + *	Recalculate dev->features set and send notifications if it + *	has changed. Should be called after driver or hardware dependent + *	conditions might have changed that influence the features. + */ +void netdev_update_features(struct net_device *dev) +{ +	if (__netdev_update_features(dev)) +		netdev_features_change(dev);  }  EXPORT_SYMBOL(netdev_update_features);  /** + *	netdev_change_features - recalculate device features + *	@dev: the device to check + * + *	Recalculate dev->features set and send notifications even + *	if they have not changed. Should be called instead of + *	netdev_update_features() if also dev->vlan_features might + *	have changed to allow the changes to be propagated to stacked + *	VLAN devices. + */ +void netdev_change_features(struct net_device *dev) +{ +	__netdev_update_features(dev); +	netdev_features_change(dev); +} +EXPORT_SYMBOL(netdev_change_features); + +/**   *	netif_stacked_transfer_operstate -	transfer operstate   *	@rootdev: the root or lower level device to transfer state from   *	@dev: the device to transfer operstate to @@ -5389,6 +5437,10 @@ int register_netdevice(struct net_device *dev)  	dev->iflink = -1; +	ret = dev_get_valid_name(dev, dev->name); +	if (ret < 0) +		goto out; +  	/* Init, if this function is available */  	if (dev->netdev_ops->ndo_init) {  		ret = dev->netdev_ops->ndo_init(dev); @@ -5399,10 +5451,6 @@ int register_netdevice(struct net_device *dev)  		}  	} -	ret = dev_get_valid_name(dev, dev->name, 0); -	if (ret) -		goto err_uninit; -  	dev->ifindex = dev_new_index(net);  	if (dev->iflink == -1)  		dev->iflink = dev->ifindex; @@ -5414,6 +5462,14 @@ int register_netdevice(struct net_device *dev)  	dev->features |= NETIF_F_SOFT_FEATURES;  	dev->wanted_features = dev->features & dev->hw_features; +	/* Turn on no cache copy if HW is doing checksum */ +	dev->hw_features |= NETIF_F_NOCACHE_COPY; +	if ((dev->features & NETIF_F_ALL_CSUM) && +	    !(dev->features & NETIF_F_NO_CSUM)) { +		dev->wanted_features |= NETIF_F_NOCACHE_COPY; +		dev->features |= NETIF_F_NOCACHE_COPY; +	} +  	/* Enable GRO and NETIF_F_HIGHDMA for vlans by default,  	 * vlan_dev_init() will do the dev->features check, so these features  	 * are enabled only if supported by underlying device. @@ -5430,7 +5486,7 @@ int register_netdevice(struct net_device *dev)  		goto err_uninit;  	dev->reg_state = NETREG_REGISTERED; -	netdev_update_features(dev); +	__netdev_update_features(dev);  	/*  	 *	Default initial state at registry is that the @@ -5527,19 +5583,7 @@ int register_netdev(struct net_device *dev)  	int err;  	rtnl_lock(); - -	/* -	 * If the name is a format string the caller wants us to do a -	 * name allocation. -	 */ -	if (strchr(dev->name, '%')) { -		err = dev_alloc_name(dev, dev->name); -		if (err < 0) -			goto out; -	} -  	err = register_netdevice(dev); -out:  	rtnl_unlock();  	return err;  } @@ -6021,7 +6065,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  		/* We get here if we can't use the current device name */  		if (!pat)  			goto out; -		if (dev_get_valid_name(dev, pat, 1)) +		if (dev_get_valid_name(dev, pat) < 0)  			goto out;  	} @@ -6153,29 +6197,20 @@ static int dev_cpu_callback(struct notifier_block *nfb,   */  u32 netdev_increment_features(u32 all, u32 one, u32 mask)  { -	/* If device needs checksumming, downgrade to it. */ -	if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) -		all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM); -	else if (mask & NETIF_F_ALL_CSUM) { -		/* If one device supports v4/v6 checksumming, set for all. */ -		if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) && -		    !(all & NETIF_F_GEN_CSUM)) { -			all &= ~NETIF_F_ALL_CSUM; -			all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); -		} +	if (mask & NETIF_F_GEN_CSUM) +		mask |= NETIF_F_ALL_CSUM; +	mask |= NETIF_F_VLAN_CHALLENGED; -		/* If one device supports hw checksumming, set for all. */ -		if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) { -			all &= ~NETIF_F_ALL_CSUM; -			all |= NETIF_F_HW_CSUM; -		} -	} +	all |= one & (NETIF_F_ONE_FOR_ALL|NETIF_F_ALL_CSUM) & mask; +	all &= one | ~NETIF_F_ALL_FOR_ALL; -	one |= NETIF_F_ALL_CSUM; +	/* If device needs checksumming, downgrade to it. */ +	if (all & (NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM)) +		all &= ~NETIF_F_NO_CSUM; -	one |= all & NETIF_F_ONE_FOR_ALL; -	all &= one | NETIF_F_LLTX | NETIF_F_GSO | NETIF_F_UFO; -	all |= one & mask & NETIF_F_ONE_FOR_ALL; +	/* If one device supports hw checksumming, set for all. */ +	if (all & NETIF_F_GEN_CSUM) +		all &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);  	return all;  }  |