diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 146 | 
1 files changed, 115 insertions, 31 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 367a586d0c8a..cf8a95f48cff 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -132,6 +132,7 @@  #include <linux/hashtable.h>  #include <linux/vmalloc.h>  #include <linux/if_macvlan.h> +#include <linux/errqueue.h>  #include "net-sysfs.h" @@ -1085,6 +1086,7 @@ static int dev_get_valid_name(struct net *net,   */  int dev_change_name(struct net_device *dev, const char *newname)  { +	unsigned char old_assign_type;  	char oldname[IFNAMSIZ];  	int err = 0;  	int ret; @@ -1112,10 +1114,17 @@ int dev_change_name(struct net_device *dev, const char *newname)  		return err;  	} +	if (oldname[0] && !strchr(oldname, '%')) +		netdev_info(dev, "renamed from %s\n", oldname); + +	old_assign_type = dev->name_assign_type; +	dev->name_assign_type = NET_NAME_RENAMED; +  rollback:  	ret = device_rename(&dev->dev, dev->name);  	if (ret) {  		memcpy(dev->name, oldname, IFNAMSIZ); +		dev->name_assign_type = old_assign_type;  		write_seqcount_end(&devnet_rename_seq);  		return ret;  	} @@ -1144,6 +1153,8 @@ rollback:  			write_seqcount_begin(&devnet_rename_seq);  			memcpy(dev->name, oldname, IFNAMSIZ);  			memcpy(oldname, newname, IFNAMSIZ); +			dev->name_assign_type = old_assign_type; +			old_assign_type = NET_NAME_RENAMED;  			goto rollback;  		} else {  			pr_err("%s: name change rollback failed: %d\n", @@ -2316,7 +2327,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth)  	 */  	if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {  		if (vlan_depth) { -			if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN))) +			if (WARN_ON(vlan_depth < VLAN_HLEN))  				return 0;  			vlan_depth -= VLAN_HLEN;  		} else { @@ -2414,8 +2425,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,  		skb_warn_bad_offload(skb); -		if (skb_header_cloned(skb) && -		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) +		err = skb_cow_head(skb, 0); +		if (err < 0)  			return ERR_PTR(err);  	} @@ -2576,13 +2587,19 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)  		return harmonize_features(skb, features);  	} -	features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | -					       NETIF_F_HW_VLAN_STAG_TX); +	features = netdev_intersect_features(features, +					     skb->dev->vlan_features | +					     NETIF_F_HW_VLAN_CTAG_TX | +					     NETIF_F_HW_VLAN_STAG_TX);  	if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) -		features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | -				NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | -				NETIF_F_HW_VLAN_STAG_TX; +		features = netdev_intersect_features(features, +						     NETIF_F_SG | +						     NETIF_F_HIGHDMA | +						     NETIF_F_FRAGLIST | +						     NETIF_F_GEN_CSUM | +						     NETIF_F_HW_VLAN_CTAG_TX | +						     NETIF_F_HW_VLAN_STAG_TX);  	return harmonize_features(skb, features);  } @@ -2745,8 +2762,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,  	/*  	 * Heuristic to force contended enqueues to serialize on a  	 * separate lock before trying to get qdisc main lock. -	 * This permits __QDISC_STATE_RUNNING owner to get the lock more often -	 * and dequeue packets faster. +	 * This permits __QDISC___STATE_RUNNING owner to get the lock more +	 * often and dequeue packets faster.  	 */  	contended = qdisc_is_running(q);  	if (unlikely(contended)) @@ -2866,6 +2883,9 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)  	skb_reset_mac_header(skb); +	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP)) +		__skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); +  	/* Disable soft irqs for various locks below. Also  	 * stops preemption for RCU.  	 */ @@ -3588,7 +3608,7 @@ another_round:  	if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||  	    skb->protocol == cpu_to_be16(ETH_P_8021AD)) { -		skb = vlan_untag(skb); +		skb = skb_vlan_untag(skb);  		if (unlikely(!skb))  			goto unlock;  	} @@ -4789,9 +4809,14 @@ static void netdev_adjacent_sysfs_del(struct net_device *dev,  	sysfs_remove_link(&(dev->dev.kobj), linkname);  } -#define netdev_adjacent_is_neigh_list(dev, dev_list) \ -		(dev_list == &dev->adj_list.upper || \ -		 dev_list == &dev->adj_list.lower) +static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev, +						 struct net_device *adj_dev, +						 struct list_head *dev_list) +{ +	return (dev_list == &dev->adj_list.upper || +		dev_list == &dev->adj_list.lower) && +		net_eq(dev_net(dev), dev_net(adj_dev)); +}  static int __netdev_adjacent_dev_insert(struct net_device *dev,  					struct net_device *adj_dev, @@ -4821,7 +4846,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,  	pr_debug("dev_hold for %s, because of link added from %s to %s\n",  		 adj_dev->name, dev->name, adj_dev->name); -	if (netdev_adjacent_is_neigh_list(dev, dev_list)) { +	if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) {  		ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list);  		if (ret)  			goto free_adj; @@ -4842,7 +4867,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,  	return 0;  remove_symlinks: -	if (netdev_adjacent_is_neigh_list(dev, dev_list)) +	if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))  		netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);  free_adj:  	kfree(adj); @@ -4875,7 +4900,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,  	if (adj->master)  		sysfs_remove_link(&(dev->dev.kobj), "master"); -	if (netdev_adjacent_is_neigh_list(dev, dev_list)) +	if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))  		netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);  	list_del_rcu(&adj->list); @@ -5145,11 +5170,65 @@ void netdev_upper_dev_unlink(struct net_device *dev,  }  EXPORT_SYMBOL(netdev_upper_dev_unlink); +void netdev_adjacent_add_links(struct net_device *dev) +{ +	struct netdev_adjacent *iter; + +	struct net *net = dev_net(dev); + +	list_for_each_entry(iter, &dev->adj_list.upper, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue; +		netdev_adjacent_sysfs_add(iter->dev, dev, +					  &iter->dev->adj_list.lower); +		netdev_adjacent_sysfs_add(dev, iter->dev, +					  &dev->adj_list.upper); +	} + +	list_for_each_entry(iter, &dev->adj_list.lower, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue; +		netdev_adjacent_sysfs_add(iter->dev, dev, +					  &iter->dev->adj_list.upper); +		netdev_adjacent_sysfs_add(dev, iter->dev, +					  &dev->adj_list.lower); +	} +} + +void netdev_adjacent_del_links(struct net_device *dev) +{ +	struct netdev_adjacent *iter; + +	struct net *net = dev_net(dev); + +	list_for_each_entry(iter, &dev->adj_list.upper, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue; +		netdev_adjacent_sysfs_del(iter->dev, dev->name, +					  &iter->dev->adj_list.lower); +		netdev_adjacent_sysfs_del(dev, iter->dev->name, +					  &dev->adj_list.upper); +	} + +	list_for_each_entry(iter, &dev->adj_list.lower, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue; +		netdev_adjacent_sysfs_del(iter->dev, dev->name, +					  &iter->dev->adj_list.upper); +		netdev_adjacent_sysfs_del(dev, iter->dev->name, +					  &dev->adj_list.lower); +	} +} +  void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)  {  	struct netdev_adjacent *iter; +	struct net *net = dev_net(dev); +  	list_for_each_entry(iter, &dev->adj_list.upper, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue;  		netdev_adjacent_sysfs_del(iter->dev, oldname,  					  &iter->dev->adj_list.lower);  		netdev_adjacent_sysfs_add(iter->dev, dev, @@ -5157,6 +5236,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)  	}  	list_for_each_entry(iter, &dev->adj_list.lower, list) { +		if (!net_eq(net,dev_net(iter->dev))) +			continue;  		netdev_adjacent_sysfs_del(iter->dev, oldname,  					  &iter->dev->adj_list.upper);  		netdev_adjacent_sysfs_add(iter->dev, dev, @@ -5440,13 +5521,9 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags)  	 */  	ret = 0; -	if ((old_flags ^ flags) & IFF_UP) {	/* Bit is different  ? */ +	if ((old_flags ^ flags) & IFF_UP)  		ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); -		if (!ret) -			dev_set_rx_mode(dev); -	} -  	if ((flags ^ dev->gflags) & IFF_PROMISC) {  		int inc = (flags & IFF_PROMISC) ? 1 : -1;  		unsigned int old_flags = dev->flags; @@ -6446,17 +6523,19 @@ void netdev_freemem(struct net_device *dev)  /**   *	alloc_netdev_mqs - allocate network device - *	@sizeof_priv:	size of private data to allocate space for - *	@name:		device name format string - *	@setup:		callback to initialize device - *	@txqs:		the number of TX subqueues to allocate - *	@rxqs:		the number of RX subqueues to allocate + *	@sizeof_priv:		size of private data to allocate space for + *	@name:			device name format string + *	@name_assign_type: 	origin of device name + *	@setup:			callback to initialize device + *	@txqs:			the number of TX subqueues to allocate + *	@rxqs:			the number of RX subqueues to allocate   *   *	Allocates a struct net_device with private data area for driver use   *	and performs basic initialization.  Also allocates subqueue structs   *	for each queue on the device.   */  struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, +		unsigned char name_assign_type,  		void (*setup)(struct net_device *),  		unsigned int txqs, unsigned int rxqs)  { @@ -6535,6 +6614,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,  #endif  	strcpy(dev->name, name); +	dev->name_assign_type = name_assign_type;  	dev->group = INIT_NETDEV_GROUP;  	if (!dev->ethtool_ops)  		dev->ethtool_ops = &default_ethtool_ops; @@ -6760,6 +6840,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  	/* Send a netdev-removed uevent to the old namespace */  	kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); +	netdev_adjacent_del_links(dev);  	/* Actually switch the network namespace */  	dev_net_set(dev, net); @@ -6774,6 +6855,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  	/* Send a netdev-add uevent to the new namespace */  	kobject_uevent(&dev->dev.kobj, KOBJ_ADD); +	netdev_adjacent_add_links(dev);  	/* Fixup kobjects */  	err = device_rename(&dev->dev, dev->name); @@ -6946,12 +7028,14 @@ static int __netdev_printk(const char *level, const struct net_device *dev,  	if (dev && dev->dev.parent) {  		r = dev_printk_emit(level[1] - '0',  				    dev->dev.parent, -				    "%s %s %s: %pV", +				    "%s %s %s%s: %pV",  				    dev_driver_string(dev->dev.parent),  				    dev_name(dev->dev.parent), -				    netdev_name(dev), vaf); +				    netdev_name(dev), netdev_reg_state(dev), +				    vaf);  	} else if (dev) { -		r = printk("%s%s: %pV", level, netdev_name(dev), vaf); +		r = printk("%s%s%s: %pV", level, netdev_name(dev), +			   netdev_reg_state(dev), vaf);  	} else {  		r = printk("%s(NULL net_device): %pV", level, vaf);  	} @@ -7103,7 +7187,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)  	rtnl_lock_unregistering(net_list);  	list_for_each_entry(net, net_list, exit_list) {  		for_each_netdev_reverse(net, dev) { -			if (dev->rtnl_link_ops) +			if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink)  				dev->rtnl_link_ops->dellink(dev, &dev_kill_list);  			else  				unregister_netdevice_queue(dev, &dev_kill_list);  |