diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 195 | 
1 files changed, 139 insertions, 56 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 7df6c9617321..4906b44af850 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4690,10 +4690,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,  		break;  	default:  		bpf_warn_invalid_xdp_action(act); -		/* fall through */ +		fallthrough;  	case XDP_ABORTED:  		trace_xdp_exception(skb->dev, xdp_prog, act); -		/* fall through */ +		fallthrough;  	case XDP_DROP:  	do_drop:  		kfree_skb(skb); @@ -6612,12 +6612,13 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,  		netdev_err_once(dev, "%s() called with weight %d\n", __func__,  				weight);  	napi->weight = weight; -	list_add(&napi->dev_list, &dev->napi_list);  	napi->dev = dev;  #ifdef CONFIG_NETPOLL  	napi->poll_owner = -1;  #endif  	set_bit(NAPI_STATE_SCHED, &napi->state); +	set_bit(NAPI_STATE_NPSVC, &napi->state); +	list_add_rcu(&napi->dev_list, &dev->napi_list);  	napi_hash_add(napi);  }  EXPORT_SYMBOL(netif_napi_add); @@ -6811,9 +6812,10 @@ 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, +				    struct netdev_nested_priv *priv)  { -	struct net_device *dev = data; +	struct net_device *dev = (struct net_device *)priv->data;  	return upper_dev == dev;  } @@ -6830,10 +6832,14 @@ static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)  bool netdev_has_upper_dev(struct net_device *dev,  			  struct net_device *upper_dev)  { +	struct netdev_nested_priv priv = { +		.data = (void *)upper_dev, +	}; +  	ASSERT_RTNL();  	return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, -					     upper_dev); +					     &priv);  }  EXPORT_SYMBOL(netdev_has_upper_dev); @@ -6850,8 +6856,12 @@ EXPORT_SYMBOL(netdev_has_upper_dev);  bool netdev_has_upper_dev_all_rcu(struct net_device *dev,  				  struct net_device *upper_dev)  { +	struct netdev_nested_priv priv = { +		.data = (void *)upper_dev, +	}; +  	return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, -					       upper_dev); +					       &priv);  }  EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); @@ -6996,8 +7006,8 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,  static int __netdev_walk_all_upper_dev(struct net_device *dev,  				       int (*fn)(struct net_device *dev, -						 void *data), -				       void *data) +					 struct netdev_nested_priv *priv), +				       struct netdev_nested_priv *priv)  {  	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];  	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; @@ -7009,7 +7019,7 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,  	while (1) {  		if (now != dev) { -			ret = fn(now, data); +			ret = fn(now, priv);  			if (ret)  				return ret;  		} @@ -7045,8 +7055,8 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,  int netdev_walk_all_upper_dev_rcu(struct net_device *dev,  				  int (*fn)(struct net_device *dev, -					    void *data), -				  void *data) +					    struct netdev_nested_priv *priv), +				  struct netdev_nested_priv *priv)  {  	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];  	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; @@ -7057,7 +7067,7 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev,  	while (1) {  		if (now != dev) { -			ret = fn(now, data); +			ret = fn(now, priv);  			if (ret)  				return ret;  		} @@ -7093,10 +7103,15 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);  static bool __netdev_has_upper_dev(struct net_device *dev,  				   struct net_device *upper_dev)  { +	struct netdev_nested_priv priv = { +		.flags = 0, +		.data = (void *)upper_dev, +	}; +  	ASSERT_RTNL();  	return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev, -					   upper_dev); +					   &priv);  }  /** @@ -7214,8 +7229,8 @@ static struct net_device *__netdev_next_lower_dev(struct net_device *dev,  int netdev_walk_all_lower_dev(struct net_device *dev,  			      int (*fn)(struct net_device *dev, -					void *data), -			      void *data) +					struct netdev_nested_priv *priv), +			      struct netdev_nested_priv *priv)  {  	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];  	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; @@ -7226,7 +7241,7 @@ int netdev_walk_all_lower_dev(struct net_device *dev,  	while (1) {  		if (now != dev) { -			ret = fn(now, data); +			ret = fn(now, priv);  			if (ret)  				return ret;  		} @@ -7261,8 +7276,8 @@ 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 netdev_nested_priv *priv), +				       struct netdev_nested_priv *priv)  {  	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];  	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; @@ -7274,7 +7289,7 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,  	while (1) {  		if (now != dev) { -			ret = fn(now, data); +			ret = fn(now, priv);  			if (ret)  				return ret;  		} @@ -7363,22 +7378,34 @@ static u8 __netdev_lower_depth(struct net_device *dev)  	return max_depth;  } -static int __netdev_update_upper_level(struct net_device *dev, void *data) +static int __netdev_update_upper_level(struct net_device *dev, +				       struct netdev_nested_priv *__unused)  {  	dev->upper_level = __netdev_upper_depth(dev) + 1;  	return 0;  } -static int __netdev_update_lower_level(struct net_device *dev, void *data) +static int __netdev_update_lower_level(struct net_device *dev, +				       struct netdev_nested_priv *priv)  {  	dev->lower_level = __netdev_lower_depth(dev) + 1; + +#ifdef CONFIG_LOCKDEP +	if (!priv) +		return 0; + +	if (priv->flags & NESTED_SYNC_IMM) +		dev->nested_level = dev->lower_level - 1; +	if (priv->flags & NESTED_SYNC_TODO) +		net_unlink_todo(dev); +#endif  	return 0;  }  int netdev_walk_all_lower_dev_rcu(struct net_device *dev,  				  int (*fn)(struct net_device *dev, -					    void *data), -				  void *data) +					    struct netdev_nested_priv *priv), +				  struct netdev_nested_priv *priv)  {  	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];  	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; @@ -7389,7 +7416,7 @@ int netdev_walk_all_lower_dev_rcu(struct net_device *dev,  	while (1) {  		if (now != dev) { -			ret = fn(now, data); +			ret = fn(now, priv);  			if (ret)  				return ret;  		} @@ -7649,6 +7676,7 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,  static int __netdev_upper_dev_link(struct net_device *dev,  				   struct net_device *upper_dev, bool master,  				   void *upper_priv, void *upper_info, +				   struct netdev_nested_priv *priv,  				   struct netlink_ext_ack *extack)  {  	struct netdev_notifier_changeupper_info changeupper_info = { @@ -7705,9 +7733,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,  	__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_update_lower_level(upper_dev, priv);  	__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, -				    NULL); +				    priv);  	return 0; @@ -7732,8 +7760,13 @@ int netdev_upper_dev_link(struct net_device *dev,  			  struct net_device *upper_dev,  			  struct netlink_ext_ack *extack)  { +	struct netdev_nested_priv priv = { +		.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO, +		.data = NULL, +	}; +  	return __netdev_upper_dev_link(dev, upper_dev, false, -				       NULL, NULL, extack); +				       NULL, NULL, &priv, extack);  }  EXPORT_SYMBOL(netdev_upper_dev_link); @@ -7756,21 +7789,19 @@ int netdev_master_upper_dev_link(struct net_device *dev,  				 void *upper_priv, void *upper_info,  				 struct netlink_ext_ack *extack)  { +	struct netdev_nested_priv priv = { +		.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO, +		.data = NULL, +	}; +  	return __netdev_upper_dev_link(dev, upper_dev, true, -				       upper_priv, upper_info, extack); +				       upper_priv, upper_info, &priv, extack);  }  EXPORT_SYMBOL(netdev_master_upper_dev_link); -/** - * netdev_upper_dev_unlink - Removes a link to upper device - * @dev: device - * @upper_dev: new upper device - * - * Removes a link to device which is upper to this one. The caller must hold - * the RTNL lock. - */ -void netdev_upper_dev_unlink(struct net_device *dev, -			     struct net_device *upper_dev) +static void __netdev_upper_dev_unlink(struct net_device *dev, +				      struct net_device *upper_dev, +				      struct netdev_nested_priv *priv)  {  	struct netdev_notifier_changeupper_info changeupper_info = {  		.info = { @@ -7795,9 +7826,28 @@ void netdev_upper_dev_unlink(struct net_device *dev,  	__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_update_lower_level(upper_dev, priv);  	__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, -				    NULL); +				    priv); +} + +/** + * netdev_upper_dev_unlink - Removes a link to upper device + * @dev: device + * @upper_dev: new upper device + * + * Removes a link to device which is upper to this one. The caller must hold + * the RTNL lock. + */ +void netdev_upper_dev_unlink(struct net_device *dev, +			     struct net_device *upper_dev) +{ +	struct netdev_nested_priv priv = { +		.flags = NESTED_SYNC_TODO, +		.data = NULL, +	}; + +	__netdev_upper_dev_unlink(dev, upper_dev, &priv);  }  EXPORT_SYMBOL(netdev_upper_dev_unlink); @@ -7833,6 +7883,10 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,  				   struct net_device *dev,  				   struct netlink_ext_ack *extack)  { +	struct netdev_nested_priv priv = { +		.flags = 0, +		.data = NULL, +	};  	int err;  	if (!new_dev) @@ -7840,8 +7894,8 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,  	if (old_dev && new_dev != old_dev)  		netdev_adjacent_dev_disable(dev, old_dev); - -	err = netdev_upper_dev_link(new_dev, dev, extack); +	err = __netdev_upper_dev_link(new_dev, dev, false, NULL, NULL, &priv, +				      extack);  	if (err) {  		if (old_dev && new_dev != old_dev)  			netdev_adjacent_dev_enable(dev, old_dev); @@ -7856,6 +7910,11 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,  				   struct net_device *new_dev,  				   struct net_device *dev)  { +	struct netdev_nested_priv priv = { +		.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO, +		.data = NULL, +	}; +  	if (!new_dev || !old_dev)  		return; @@ -7863,7 +7922,7 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,  		return;  	netdev_adjacent_dev_enable(dev, old_dev); -	netdev_upper_dev_unlink(old_dev, dev); +	__netdev_upper_dev_unlink(old_dev, dev, &priv);  }  EXPORT_SYMBOL(netdev_adjacent_change_commit); @@ -7871,13 +7930,18 @@ void netdev_adjacent_change_abort(struct net_device *old_dev,  				  struct net_device *new_dev,  				  struct net_device *dev)  { +	struct netdev_nested_priv priv = { +		.flags = 0, +		.data = NULL, +	}; +  	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); +	__netdev_upper_dev_unlink(new_dev, dev, &priv);  }  EXPORT_SYMBOL(netdev_adjacent_change_abort); @@ -8646,7 +8710,7 @@ int dev_get_port_parent_id(struct net_device *dev,  		if (!first.id_len)  			first = *ppid;  		else if (memcmp(&first, ppid, sizeof(*ppid))) -			return -ENODATA; +			return -EOPNOTSUPP;  	}  	return err; @@ -8742,13 +8806,15 @@ struct bpf_xdp_link {  	int flags;  }; -static enum bpf_xdp_mode dev_xdp_mode(u32 flags) +static enum bpf_xdp_mode dev_xdp_mode(struct net_device *dev, u32 flags)  {  	if (flags & XDP_FLAGS_HW_MODE)  		return XDP_MODE_HW;  	if (flags & XDP_FLAGS_DRV_MODE)  		return XDP_MODE_DRV; -	return XDP_MODE_SKB; +	if (flags & XDP_FLAGS_SKB_MODE) +		return XDP_MODE_SKB; +	return dev->netdev_ops->ndo_bpf ? XDP_MODE_DRV : XDP_MODE_SKB;  }  static bpf_op_t dev_xdp_bpf_op(struct net_device *dev, enum bpf_xdp_mode mode) @@ -8896,7 +8962,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack  		return -EINVAL;  	} -	mode = dev_xdp_mode(flags); +	mode = dev_xdp_mode(dev, flags);  	/* can't replace attached link */  	if (dev_xdp_link(dev, mode)) {  		NL_SET_ERR_MSG(extack, "Can't replace active BPF XDP link"); @@ -8913,10 +8979,6 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack  		NL_SET_ERR_MSG(extack, "Active program does not match expected");  		return -EEXIST;  	} -	if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) && cur_prog) { -		NL_SET_ERR_MSG(extack, "XDP program already attached"); -		return -EBUSY; -	}  	/* put effective new program into new_prog */  	if (link) @@ -8927,6 +8989,10 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack  		enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB  					       ? XDP_MODE_DRV : XDP_MODE_SKB; +		if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) && cur_prog) { +			NL_SET_ERR_MSG(extack, "XDP program already attached"); +			return -EBUSY; +		}  		if (!offload && dev_xdp_prog(dev, other_mode)) {  			NL_SET_ERR_MSG(extack, "Native and generic XDP can't be active at the same time");  			return -EEXIST; @@ -8984,7 +9050,7 @@ static int dev_xdp_detach_link(struct net_device *dev,  	ASSERT_RTNL(); -	mode = dev_xdp_mode(link->flags); +	mode = dev_xdp_mode(dev, link->flags);  	if (dev_xdp_link(dev, mode) != link)  		return -EINVAL; @@ -9080,7 +9146,7 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,  		goto out_unlock;  	} -	mode = dev_xdp_mode(xdp_link->flags); +	mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags);  	bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode);  	err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL,  			      xdp_link->flags, new_prog); @@ -9164,7 +9230,7 @@ out_put_dev:  int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,  		      int fd, int expected_fd, u32 flags)  { -	enum bpf_xdp_mode mode = dev_xdp_mode(flags); +	enum bpf_xdp_mode mode = dev_xdp_mode(dev, flags);  	struct bpf_prog *new_prog = NULL, *old_prog = NULL;  	int err; @@ -10059,6 +10125,19 @@ static void netdev_wait_allrefs(struct net_device *dev)  void netdev_run_todo(void)  {  	struct list_head list; +#ifdef CONFIG_LOCKDEP +	struct list_head unlink_list; + +	list_replace_init(&net_unlink_list, &unlink_list); + +	while (!list_empty(&unlink_list)) { +		struct net_device *dev = list_first_entry(&unlink_list, +							  struct net_device, +							  unlink_list); +		list_del(&dev->unlink_list); +		dev->nested_level = dev->lower_level - 1; +	} +#endif  	/* Snapshot list, allow later requests */  	list_replace_init(&net_todo_list, &list); @@ -10271,6 +10350,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,  	dev->gso_max_segs = GSO_MAX_SEGS;  	dev->upper_level = 1;  	dev->lower_level = 1; +#ifdef CONFIG_LOCKDEP +	dev->nested_level = 0; +	INIT_LIST_HEAD(&dev->unlink_list); +#endif  	INIT_LIST_HEAD(&dev->napi_list);  	INIT_LIST_HEAD(&dev->unreg_list);  |