diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 620 | ||||
| -rw-r--r-- | net/core/dev_addr_lists.c | 12 | ||||
| -rw-r--r-- | net/core/ethtool.c | 4 | ||||
| -rw-r--r-- | net/core/flow_dissector.c | 38 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 18 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 15 | ||||
| -rw-r--r-- | net/core/skbuff.c | 21 | 
7 files changed, 520 insertions, 208 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index bf3ed413abaf..96afd464284a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -146,6 +146,7 @@  #include "net-sysfs.h"  #define MAX_GRO_SKBS 8 +#define MAX_NEST_DEV 8  /* This should be increased if a protocol with a bigger head is added. */  #define GRO_MAX_HEAD (MAX_HEADER + 128) @@ -276,88 +277,6 @@ static RAW_NOTIFIER_HEAD(netdev_chain);  DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);  EXPORT_PER_CPU_SYMBOL(softnet_data); -#ifdef CONFIG_LOCKDEP -/* - * register_netdevice() inits txq->_xmit_lock and sets lockdep class - * according to dev->type - */ -static const unsigned short netdev_lock_type[] = { -	 ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, -	 ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, -	 ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, -	 ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, -	 ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, -	 ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, -	 ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, -	 ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, -	 ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, -	 ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, -	 ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, -	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, -	 ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, -	 ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, -	 ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; - -static const char *const netdev_lock_name[] = { -	"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", -	"_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", -	"_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", -	"_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", -	"_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", -	"_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", -	"_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", -	"_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", -	"_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", -	"_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", -	"_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", -	"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", -	"_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", -	"_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE", -	"_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; - -static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; -static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; - -static inline unsigned short netdev_lock_pos(unsigned short dev_type) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++) -		if (netdev_lock_type[i] == dev_type) -			return i; -	/* the last key is used by default */ -	return ARRAY_SIZE(netdev_lock_type) - 1; -} - -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, -						 unsigned short dev_type) -{ -	int i; - -	i = netdev_lock_pos(dev_type); -	lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i], -				   netdev_lock_name[i]); -} - -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -	int i; - -	i = netdev_lock_pos(dev->type); -	lockdep_set_class_and_name(&dev->addr_list_lock, -				   &netdev_addr_lock_key[i], -				   netdev_lock_name[i]); -} -#else -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, -						 unsigned short dev_type) -{ -} -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -} -#endif -  /*******************************************************************************   *   *		Protocol management and registration routines @@ -6489,6 +6408,9 @@ struct netdev_adjacent {  	/* upper master flag, there can only be one master device per list */  	bool master; +	/* lookup ignore flag */ +	bool ignore; +  	/* counter for the number of times this device was added to us */  	u16 ref_nr; @@ -6511,7 +6433,7 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,  	return NULL;  } -static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data) +static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)  {  	struct net_device *dev = data; @@ -6532,7 +6454,7 @@ bool netdev_has_upper_dev(struct net_device *dev,  {  	ASSERT_RTNL(); -	return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, +	return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,  					     upper_dev);  }  EXPORT_SYMBOL(netdev_has_upper_dev); @@ -6550,7 +6472,7 @@ EXPORT_SYMBOL(netdev_has_upper_dev);  bool netdev_has_upper_dev_all_rcu(struct net_device *dev,  				  struct net_device *upper_dev)  { -	return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, +	return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,  					       upper_dev);  }  EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); @@ -6594,6 +6516,22 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)  }  EXPORT_SYMBOL(netdev_master_upper_dev_get); +static struct net_device *__netdev_master_upper_dev_get(struct net_device *dev) +{ +	struct netdev_adjacent *upper; + +	ASSERT_RTNL(); + +	if (list_empty(&dev->adj_list.upper)) +		return NULL; + +	upper = list_first_entry(&dev->adj_list.upper, +				 struct netdev_adjacent, list); +	if (likely(upper->master) && !upper->ignore) +		return upper->dev; +	return NULL; +} +  /**   * netdev_has_any_lower_dev - Check if device is linked to some device   * @dev: device @@ -6644,6 +6582,23 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,  }  EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); +static struct net_device *__netdev_next_upper_dev(struct net_device *dev, +						  struct list_head **iter, +						  bool *ignore) +{ +	struct netdev_adjacent *upper; + +	upper = list_entry((*iter)->next, struct netdev_adjacent, list); + +	if (&upper->list == &dev->adj_list.upper) +		return NULL; + +	*iter = &upper->list; +	*ignore = upper->ignore; + +	return upper->dev; +} +  static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,  						    struct list_head **iter)  { @@ -6661,34 +6616,111 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,  	return upper->dev;  } +static int __netdev_walk_all_upper_dev(struct net_device *dev, +				       int (*fn)(struct net_device *dev, +						 void *data), +				       void *data) +{ +	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; +	bool ignore; + +	now = dev; +	iter = &dev->adj_list.upper; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			udev = __netdev_next_upper_dev(now, &iter, &ignore); +			if (!udev) +				break; +			if (ignore) +				continue; + +			next = udev; +			niter = &udev->adj_list.upper; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter; +	} + +	return 0; +} +  int netdev_walk_all_upper_dev_rcu(struct net_device *dev,  				  int (*fn)(struct net_device *dev,  					    void *data),  				  void *data)  { -	struct net_device *udev; -	struct list_head *iter; -	int ret; +	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; -	for (iter = &dev->adj_list.upper, -	     udev = netdev_next_upper_dev_rcu(dev, &iter); -	     udev; -	     udev = netdev_next_upper_dev_rcu(dev, &iter)) { -		/* first is the upper device itself */ -		ret = fn(udev, data); -		if (ret) -			return ret; +	now = dev; +	iter = &dev->adj_list.upper; -		/* then look at all of its upper devices */ -		ret = netdev_walk_all_upper_dev_rcu(udev, fn, data); -		if (ret) -			return ret; +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			udev = netdev_next_upper_dev_rcu(now, &iter); +			if (!udev) +				break; + +			next = udev; +			niter = &udev->adj_list.upper; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0;  }  EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); +static bool __netdev_has_upper_dev(struct net_device *dev, +				   struct net_device *upper_dev) +{ +	ASSERT_RTNL(); + +	return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev, +					   upper_dev); +} +  /**   * netdev_lower_get_next_private - Get the next ->private from the   *				   lower neighbour list @@ -6785,34 +6817,119 @@ static struct net_device *netdev_next_lower_dev(struct net_device *dev,  	return lower->dev;  } +static struct net_device *__netdev_next_lower_dev(struct net_device *dev, +						  struct list_head **iter, +						  bool *ignore) +{ +	struct netdev_adjacent *lower; + +	lower = list_entry((*iter)->next, struct netdev_adjacent, list); + +	if (&lower->list == &dev->adj_list.lower) +		return NULL; + +	*iter = &lower->list; +	*ignore = lower->ignore; + +	return lower->dev; +} +  int netdev_walk_all_lower_dev(struct net_device *dev,  			      int (*fn)(struct net_device *dev,  					void *data),  			      void *data)  { -	struct net_device *ldev; -	struct list_head *iter; -	int ret; +	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; -	for (iter = &dev->adj_list.lower, -	     ldev = netdev_next_lower_dev(dev, &iter); -	     ldev; -	     ldev = netdev_next_lower_dev(dev, &iter)) { -		/* first is the lower device itself */ -		ret = fn(ldev, data); -		if (ret) -			return ret; +	now = dev; +	iter = &dev->adj_list.lower; -		/* then look at all of its lower devices */ -		ret = netdev_walk_all_lower_dev(ldev, fn, data); -		if (ret) -			return ret; +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = netdev_next_lower_dev(now, &iter); +			if (!ldev) +				break; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0;  }  EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev); +static int __netdev_walk_all_lower_dev(struct net_device *dev, +				       int (*fn)(struct net_device *dev, +						 void *data), +				       void *data) +{ +	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; +	bool ignore; + +	now = dev; +	iter = &dev->adj_list.lower; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = __netdev_next_lower_dev(now, &iter, &ignore); +			if (!ldev) +				break; +			if (ignore) +				continue; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter; +	} + +	return 0; +} +  static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,  						    struct list_head **iter)  { @@ -6827,28 +6944,99 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,  	return lower->dev;  } -int netdev_walk_all_lower_dev_rcu(struct net_device *dev, -				  int (*fn)(struct net_device *dev, -					    void *data), -				  void *data) +static u8 __netdev_upper_depth(struct net_device *dev) +{ +	struct net_device *udev; +	struct list_head *iter; +	u8 max_depth = 0; +	bool ignore; + +	for (iter = &dev->adj_list.upper, +	     udev = __netdev_next_upper_dev(dev, &iter, &ignore); +	     udev; +	     udev = __netdev_next_upper_dev(dev, &iter, &ignore)) { +		if (ignore) +			continue; +		if (max_depth < udev->upper_level) +			max_depth = udev->upper_level; +	} + +	return max_depth; +} + +static u8 __netdev_lower_depth(struct net_device *dev)  {  	struct net_device *ldev;  	struct list_head *iter; -	int ret; +	u8 max_depth = 0; +	bool ignore;  	for (iter = &dev->adj_list.lower, -	     ldev = netdev_next_lower_dev_rcu(dev, &iter); +	     ldev = __netdev_next_lower_dev(dev, &iter, &ignore);  	     ldev; -	     ldev = netdev_next_lower_dev_rcu(dev, &iter)) { -		/* first is the lower device itself */ -		ret = fn(ldev, data); -		if (ret) -			return ret; +	     ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) { +		if (ignore) +			continue; +		if (max_depth < ldev->lower_level) +			max_depth = ldev->lower_level; +	} -		/* then look at all of its lower devices */ -		ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data); -		if (ret) -			return ret; +	return max_depth; +} + +static int __netdev_update_upper_level(struct net_device *dev, void *data) +{ +	dev->upper_level = __netdev_upper_depth(dev) + 1; +	return 0; +} + +static int __netdev_update_lower_level(struct net_device *dev, void *data) +{ +	dev->lower_level = __netdev_lower_depth(dev) + 1; +	return 0; +} + +int netdev_walk_all_lower_dev_rcu(struct net_device *dev, +				  int (*fn)(struct net_device *dev, +					    void *data), +				  void *data) +{ +	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; + +	now = dev; +	iter = &dev->adj_list.lower; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = netdev_next_lower_dev_rcu(now, &iter); +			if (!ldev) +				break; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0; @@ -6952,6 +7140,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,  	adj->master = master;  	adj->ref_nr = 1;  	adj->private = private; +	adj->ignore = false;  	dev_hold(adj_dev);  	pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", @@ -7102,14 +7291,17 @@ static int __netdev_upper_dev_link(struct net_device *dev,  		return -EBUSY;  	/* To prevent loops, check if dev is not upper device to upper_dev. */ -	if (netdev_has_upper_dev(upper_dev, dev)) +	if (__netdev_has_upper_dev(upper_dev, dev))  		return -EBUSY; +	if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV) +		return -EMLINK; +  	if (!master) { -		if (netdev_has_upper_dev(dev, upper_dev)) +		if (__netdev_has_upper_dev(dev, upper_dev))  			return -EEXIST;  	} else { -		master_dev = netdev_master_upper_dev_get(dev); +		master_dev = __netdev_master_upper_dev_get(dev);  		if (master_dev)  			return master_dev == upper_dev ? -EEXIST : -EBUSY;  	} @@ -7131,6 +7323,13 @@ static int __netdev_upper_dev_link(struct net_device *dev,  	if (ret)  		goto rollback; +	__netdev_update_upper_level(dev, NULL); +	__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); + +	__netdev_update_lower_level(upper_dev, NULL); +	__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, +				    NULL); +  	return 0;  rollback: @@ -7213,9 +7412,96 @@ void netdev_upper_dev_unlink(struct net_device *dev,  	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,  				      &changeupper_info.info); + +	__netdev_update_upper_level(dev, NULL); +	__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); + +	__netdev_update_lower_level(upper_dev, NULL); +	__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, +				    NULL);  }  EXPORT_SYMBOL(netdev_upper_dev_unlink); +static void __netdev_adjacent_dev_set(struct net_device *upper_dev, +				      struct net_device *lower_dev, +				      bool val) +{ +	struct netdev_adjacent *adj; + +	adj = __netdev_find_adj(lower_dev, &upper_dev->adj_list.lower); +	if (adj) +		adj->ignore = val; + +	adj = __netdev_find_adj(upper_dev, &lower_dev->adj_list.upper); +	if (adj) +		adj->ignore = val; +} + +static void netdev_adjacent_dev_disable(struct net_device *upper_dev, +					struct net_device *lower_dev) +{ +	__netdev_adjacent_dev_set(upper_dev, lower_dev, true); +} + +static void netdev_adjacent_dev_enable(struct net_device *upper_dev, +				       struct net_device *lower_dev) +{ +	__netdev_adjacent_dev_set(upper_dev, lower_dev, false); +} + +int netdev_adjacent_change_prepare(struct net_device *old_dev, +				   struct net_device *new_dev, +				   struct net_device *dev, +				   struct netlink_ext_ack *extack) +{ +	int err; + +	if (!new_dev) +		return 0; + +	if (old_dev && new_dev != old_dev) +		netdev_adjacent_dev_disable(dev, old_dev); + +	err = netdev_upper_dev_link(new_dev, dev, extack); +	if (err) { +		if (old_dev && new_dev != old_dev) +			netdev_adjacent_dev_enable(dev, old_dev); +		return err; +	} + +	return 0; +} +EXPORT_SYMBOL(netdev_adjacent_change_prepare); + +void netdev_adjacent_change_commit(struct net_device *old_dev, +				   struct net_device *new_dev, +				   struct net_device *dev) +{ +	if (!new_dev || !old_dev) +		return; + +	if (new_dev == old_dev) +		return; + +	netdev_adjacent_dev_enable(dev, old_dev); +	netdev_upper_dev_unlink(old_dev, dev); +} +EXPORT_SYMBOL(netdev_adjacent_change_commit); + +void netdev_adjacent_change_abort(struct net_device *old_dev, +				  struct net_device *new_dev, +				  struct net_device *dev) +{ +	if (!new_dev) +		return; + +	if (old_dev && new_dev != old_dev) +		netdev_adjacent_dev_enable(dev, old_dev); + +	netdev_upper_dev_unlink(new_dev, dev); +} +EXPORT_SYMBOL(netdev_adjacent_change_abort); +  /**   * netdev_bonding_info_change - Dispatch event about slave change   * @dev: device @@ -7329,25 +7615,6 @@ void *netdev_lower_dev_get_private(struct net_device *dev,  EXPORT_SYMBOL(netdev_lower_dev_get_private); -int dev_get_nest_level(struct net_device *dev) -{ -	struct net_device *lower = NULL; -	struct list_head *iter; -	int max_nest = -1; -	int nest; - -	ASSERT_RTNL(); - -	netdev_for_each_lower_dev(dev, lower, iter) { -		nest = dev_get_nest_level(lower); -		if (max_nest < nest) -			max_nest = nest; -	} - -	return max_nest + 1; -} -EXPORT_SYMBOL(dev_get_nest_level); -  /**   * netdev_lower_change - Dispatch event about lower device state change   * @lower_dev: device @@ -8619,7 +8886,7 @@ static void netdev_init_one_queue(struct net_device *dev,  {  	/* Initialize queue lock */  	spin_lock_init(&queue->_xmit_lock); -	netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); +	lockdep_set_class(&queue->_xmit_lock, &dev->qdisc_xmit_lock_key);  	queue->xmit_lock_owner = -1;  	netdev_queue_numa_node_write(queue, NUMA_NO_NODE);  	queue->dev = dev; @@ -8666,6 +8933,43 @@ void netif_tx_stop_all_queues(struct net_device *dev)  }  EXPORT_SYMBOL(netif_tx_stop_all_queues); +static void netdev_register_lockdep_key(struct net_device *dev) +{ +	lockdep_register_key(&dev->qdisc_tx_busylock_key); +	lockdep_register_key(&dev->qdisc_running_key); +	lockdep_register_key(&dev->qdisc_xmit_lock_key); +	lockdep_register_key(&dev->addr_list_lock_key); +} + +static void netdev_unregister_lockdep_key(struct net_device *dev) +{ +	lockdep_unregister_key(&dev->qdisc_tx_busylock_key); +	lockdep_unregister_key(&dev->qdisc_running_key); +	lockdep_unregister_key(&dev->qdisc_xmit_lock_key); +	lockdep_unregister_key(&dev->addr_list_lock_key); +} + +void netdev_update_lockdep_key(struct net_device *dev) +{ +	struct netdev_queue *queue; +	int i; + +	lockdep_unregister_key(&dev->qdisc_xmit_lock_key); +	lockdep_unregister_key(&dev->addr_list_lock_key); + +	lockdep_register_key(&dev->qdisc_xmit_lock_key); +	lockdep_register_key(&dev->addr_list_lock_key); + +	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key); +	for (i = 0; i < dev->num_tx_queues; i++) { +		queue = netdev_get_tx_queue(dev, i); + +		lockdep_set_class(&queue->_xmit_lock, +				  &dev->qdisc_xmit_lock_key); +	} +} +EXPORT_SYMBOL(netdev_update_lockdep_key); +  /**   *	register_netdevice	- register a network device   *	@dev: device to register @@ -8700,7 +9004,7 @@ int register_netdevice(struct net_device *dev)  	BUG_ON(!net);  	spin_lock_init(&dev->addr_list_lock); -	netdev_set_addr_lockdep_class(dev); +	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);  	ret = dev_get_valid_name(net, dev, dev->name);  	if (ret < 0) @@ -9210,8 +9514,12 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,  	dev_net_set(dev, &init_net); +	netdev_register_lockdep_key(dev); +  	dev->gso_max_size = GSO_MAX_SIZE;  	dev->gso_max_segs = GSO_MAX_SEGS; +	dev->upper_level = 1; +	dev->lower_level = 1;  	INIT_LIST_HEAD(&dev->napi_list);  	INIT_LIST_HEAD(&dev->unreg_list); @@ -9292,6 +9600,8 @@ void free_netdev(struct net_device *dev)  	free_percpu(dev->pcpu_refcnt);  	dev->pcpu_refcnt = NULL; +	netdev_unregister_lockdep_key(dev); +  	/*  Compatibility with error handling in drivers */  	if (dev->reg_state == NETREG_UNINITIALIZED) {  		netdev_freemem(dev); @@ -9460,7 +9770,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  	call_netdevice_notifiers(NETDEV_UNREGISTER, dev);  	rcu_barrier(); -	new_nsid = peernet2id_alloc(dev_net(dev), net); +	new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);  	/* If there is an ifindex conflict assign a new one */  	if (__dev_get_by_index(net, dev->ifindex))  		new_ifindex = dev_new_index(net); diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index 6393ba930097..2f949b5a1eb9 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -637,7 +637,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)  	if (to->addr_len != from->addr_len)  		return -EINVAL; -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);  	if (!err)  		__dev_set_rx_mode(to); @@ -667,7 +667,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)  	if (to->addr_len != from->addr_len)  		return -EINVAL; -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);  	if (!err)  		__dev_set_rx_mode(to); @@ -691,7 +691,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)  		return;  	netif_addr_lock_bh(from); -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);  	__dev_set_rx_mode(to);  	netif_addr_unlock(to); @@ -858,7 +858,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)  	if (to->addr_len != from->addr_len)  		return -EINVAL; -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);  	if (!err)  		__dev_set_rx_mode(to); @@ -888,7 +888,7 @@ int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)  	if (to->addr_len != from->addr_len)  		return -EINVAL; -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);  	if (!err)  		__dev_set_rx_mode(to); @@ -912,7 +912,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)  		return;  	netif_addr_lock_bh(from); -	netif_addr_lock_nested(to); +	netif_addr_lock(to);  	__hw_addr_unsync(&to->mc, &from->mc, to->addr_len);  	__dev_set_rx_mode(to);  	netif_addr_unlock(to); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index c763106c73fc..cd9bc67381b2 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1396,11 +1396,13 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)  static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)  { -	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; +	struct ethtool_wolinfo wol;  	if (!dev->ethtool_ops->get_wol)  		return -EOPNOTSUPP; +	memset(&wol, 0, sizeof(struct ethtool_wolinfo)); +	wol.cmd = ETHTOOL_GWOL;  	dev->ethtool_ops->get_wol(dev, &wol);  	if (copy_to_user(useraddr, &wol, sizeof(wol))) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7c09d87d3269..68eda10d0680 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -1350,30 +1350,21 @@ out_bad:  }  EXPORT_SYMBOL(__skb_flow_dissect); -static u32 hashrnd __read_mostly; +static siphash_key_t hashrnd __read_mostly;  static __always_inline void __flow_hash_secret_init(void)  {  	net_get_random_once(&hashrnd, sizeof(hashrnd));  } -static __always_inline u32 __flow_hash_words(const u32 *words, u32 length, -					     u32 keyval) +static const void *flow_keys_hash_start(const struct flow_keys *flow)  { -	return jhash2(words, length, keyval); -} - -static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow) -{ -	const void *p = flow; - -	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32)); -	return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET); +	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT); +	return &flow->FLOW_KEYS_HASH_START_FIELD;  }  static inline size_t flow_keys_hash_length(const struct flow_keys *flow)  {  	size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); -	BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));  	BUILD_BUG_ON(offsetof(typeof(*flow), addrs) !=  		     sizeof(*flow) - sizeof(flow->addrs)); @@ -1388,7 +1379,7 @@ static inline size_t flow_keys_hash_length(const struct flow_keys *flow)  		diff -= sizeof(flow->addrs.tipckey);  		break;  	} -	return (sizeof(*flow) - diff) / sizeof(u32); +	return sizeof(*flow) - diff;  }  __be32 flow_get_u32_src(const struct flow_keys *flow) @@ -1454,14 +1445,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)  	}  } -static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) +static inline u32 __flow_hash_from_keys(struct flow_keys *keys, +					const siphash_key_t *keyval)  {  	u32 hash;  	__flow_hash_consistentify(keys); -	hash = __flow_hash_words(flow_keys_hash_start(keys), -				 flow_keys_hash_length(keys), keyval); +	hash = siphash(flow_keys_hash_start(keys), +		       flow_keys_hash_length(keys), keyval);  	if (!hash)  		hash = 1; @@ -1471,12 +1463,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)  u32 flow_hash_from_keys(struct flow_keys *keys)  {  	__flow_hash_secret_init(); -	return __flow_hash_from_keys(keys, hashrnd); +	return __flow_hash_from_keys(keys, &hashrnd);  }  EXPORT_SYMBOL(flow_hash_from_keys);  static inline u32 ___skb_get_hash(const struct sk_buff *skb, -				  struct flow_keys *keys, u32 keyval) +				  struct flow_keys *keys, +				  const siphash_key_t *keyval)  {  	skb_flow_dissect_flow_keys(skb, keys,  				   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); @@ -1524,7 +1517,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)  			   &keys, NULL, 0, 0, 0,  			   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); -	return __flow_hash_from_keys(&keys, hashrnd); +	return __flow_hash_from_keys(&keys, &hashrnd);  }  EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); @@ -1544,13 +1537,14 @@ void __skb_get_hash(struct sk_buff *skb)  	__flow_hash_secret_init(); -	hash = ___skb_get_hash(skb, &keys, hashrnd); +	hash = ___skb_get_hash(skb, &keys, &hashrnd);  	__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));  }  EXPORT_SYMBOL(__skb_get_hash); -__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) +__u32 skb_get_hash_perturb(const struct sk_buff *skb, +			   const siphash_key_t *perturb)  {  	struct flow_keys keys; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 6d3e4821b02d..39402840025e 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -246,11 +246,11 @@ static int __peernet2id(struct net *net, struct net *peer)  }  static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, -			      struct nlmsghdr *nlh); +			      struct nlmsghdr *nlh, gfp_t gfp);  /* This function returns the id of a peer netns. If no id is assigned, one will   * be allocated and returned.   */ -int peernet2id_alloc(struct net *net, struct net *peer) +int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)  {  	bool alloc = false, alive = false;  	int id; @@ -269,7 +269,7 @@ int peernet2id_alloc(struct net *net, struct net *peer)  	id = __peernet2id_alloc(net, peer, &alloc);  	spin_unlock_bh(&net->nsid_lock);  	if (alloc && id >= 0) -		rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL); +		rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp);  	if (alive)  		put_net(peer);  	return id; @@ -479,6 +479,7 @@ struct net *copy_net_ns(unsigned long flags,  	if (rv < 0) {  put_userns: +		key_remove_domain(net->key_domain);  		put_user_ns(user_ns);  		net_drop_ns(net);  dec_ucounts: @@ -533,7 +534,8 @@ static void unhash_nsid(struct net *net, struct net *last)  			idr_remove(&tmp->netns_ids, id);  		spin_unlock_bh(&tmp->nsid_lock);  		if (id >= 0) -			rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL); +			rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL, +					  GFP_KERNEL);  		if (tmp == last)  			break;  	} @@ -766,7 +768,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,  	spin_unlock_bh(&net->nsid_lock);  	if (err >= 0) {  		rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid, -				  nlh); +				  nlh, GFP_KERNEL);  		err = 0;  	} else if (err == -ENOSPC && nsid >= 0) {  		err = -EEXIST; @@ -1054,7 +1056,7 @@ end:  }  static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, -			      struct nlmsghdr *nlh) +			      struct nlmsghdr *nlh, gfp_t gfp)  {  	struct net_fill_args fillargs = {  		.portid = portid, @@ -1065,7 +1067,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,  	struct sk_buff *msg;  	int err = -ENOMEM; -	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); +	msg = nlmsg_new(rtnl_net_get_size(), gfp);  	if (!msg)  		goto out; @@ -1073,7 +1075,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,  	if (err < 0)  		goto err_out; -	rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, 0); +	rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp);  	return;  err_out: diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1ee6460f8275..ba4b4048ec3e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1523,7 +1523,7 @@ static noinline_for_stack int nla_put_ifalias(struct sk_buff *skb,  static int rtnl_fill_link_netnsid(struct sk_buff *skb,  				  const struct net_device *dev, -				  struct net *src_net) +				  struct net *src_net, gfp_t gfp)  {  	bool put_iflink = false; @@ -1531,7 +1531,7 @@ static int rtnl_fill_link_netnsid(struct sk_buff *skb,  		struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);  		if (!net_eq(dev_net(dev), link_net)) { -			int id = peernet2id_alloc(src_net, link_net); +			int id = peernet2id_alloc(src_net, link_net, gfp);  			if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))  				return -EMSGSIZE; @@ -1589,7 +1589,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,  			    int type, u32 pid, u32 seq, u32 change,  			    unsigned int flags, u32 ext_filter_mask,  			    u32 event, int *new_nsid, int new_ifindex, -			    int tgt_netnsid) +			    int tgt_netnsid, gfp_t gfp)  {  	struct ifinfomsg *ifm;  	struct nlmsghdr *nlh; @@ -1681,7 +1681,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,  			goto nla_put_failure;  	} -	if (rtnl_fill_link_netnsid(skb, dev, src_net)) +	if (rtnl_fill_link_netnsid(skb, dev, src_net, gfp))  		goto nla_put_failure;  	if (new_nsid && @@ -2001,7 +2001,7 @@ walk_entries:  					       NETLINK_CB(cb->skb).portid,  					       nlh->nlmsg_seq, 0, flags,  					       ext_filter_mask, 0, NULL, 0, -					       netnsid); +					       netnsid, GFP_KERNEL);  			if (err < 0) {  				if (likely(skb->len)) @@ -2355,6 +2355,7 @@ static int do_set_master(struct net_device *dev, int ifindex,  			err = ops->ndo_del_slave(upper_dev, dev);  			if (err)  				return err; +			netdev_update_lockdep_key(dev);  		} else {  			return -EOPNOTSUPP;  		} @@ -3359,7 +3360,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,  	err = rtnl_fill_ifinfo(nskb, dev, net,  			       RTM_NEWLINK, NETLINK_CB(skb).portid,  			       nlh->nlmsg_seq, 0, 0, ext_filter_mask, -			       0, NULL, 0, netnsid); +			       0, NULL, 0, netnsid, GFP_KERNEL);  	if (err < 0) {  		/* -EMSGSIZE implies BUG in if_nlmsg_size */  		WARN_ON(err == -EMSGSIZE); @@ -3471,7 +3472,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,  	err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),  			       type, 0, 0, change, 0, 0, event, -			       new_nsid, new_ifindex, -1); +			       new_nsid, new_ifindex, -1, flags);  	if (err < 0) {  		/* -EMSGSIZE implies BUG in if_nlmsg_size() */  		WARN_ON(err == -EMSGSIZE); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8c178703467b..867e61df00db 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -5477,12 +5477,14 @@ static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr,   * @skb: buffer   * @mpls_lse: MPLS label stack entry to push   * @mpls_proto: ethertype of the new MPLS header (expects 0x8847 or 0x8848) + * @mac_len: length of the MAC header   *   * Expects skb->data at mac header.   *   * Returns 0 on success, -errno otherwise.   */ -int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto) +int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto, +		  int mac_len)  {  	struct mpls_shim_hdr *lse;  	int err; @@ -5499,15 +5501,15 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto)  		return err;  	if (!skb->inner_protocol) { -		skb_set_inner_network_header(skb, skb->mac_len); +		skb_set_inner_network_header(skb, mac_len);  		skb_set_inner_protocol(skb, skb->protocol);  	}  	skb_push(skb, MPLS_HLEN);  	memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb), -		skb->mac_len); +		mac_len);  	skb_reset_mac_header(skb); -	skb_set_network_header(skb, skb->mac_len); +	skb_set_network_header(skb, mac_len);  	lse = mpls_hdr(skb);  	lse->label_stack_entry = mpls_lse; @@ -5526,29 +5528,30 @@ EXPORT_SYMBOL_GPL(skb_mpls_push);   *   * @skb: buffer   * @next_proto: ethertype of header after popped MPLS header + * @mac_len: length of the MAC header   *   * Expects skb->data at mac header.   *   * Returns 0 on success, -errno otherwise.   */ -int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto) +int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len)  {  	int err;  	if (unlikely(!eth_p_mpls(skb->protocol))) -		return -EINVAL; +		return 0; -	err = skb_ensure_writable(skb, skb->mac_len + MPLS_HLEN); +	err = skb_ensure_writable(skb, mac_len + MPLS_HLEN);  	if (unlikely(err))  		return err;  	skb_postpull_rcsum(skb, mpls_hdr(skb), MPLS_HLEN);  	memmove(skb_mac_header(skb) + MPLS_HLEN, skb_mac_header(skb), -		skb->mac_len); +		mac_len);  	__skb_pull(skb, MPLS_HLEN);  	skb_reset_mac_header(skb); -	skb_set_network_header(skb, skb->mac_len); +	skb_set_network_header(skb, mac_len);  	if (skb->dev && skb->dev->type == ARPHRD_ETHER) {  		struct ethhdr *hdr; | 

