1444 lines · 37.8 KB · C
RawDownload
		goto free_msg; 	if (devlink_nl_put_handle(msg, devlink))		goto nla_put_failure; 	if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed,			       actions_performed))		goto nla_put_failure;	genlmsg_end(msg, hdr); 	return genlmsg_reply(msg, info); nla_put_failure:	genlmsg_cancel(msg, hdr);free_msg:	nlmsg_free(msg);	return -EMSGSIZE;} int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	enum devlink_reload_action action;	enum devlink_reload_limit limit;	struct net *dest_net = NULL;	u32 actions_performed;	int err; 	err = devlink_resources_validate(devlink, NULL, info);	if (err) {		NL_SET_ERR_MSG(info->extack, "resources size validation failed");		return err;	} 	action = nla_get_u8_default(info->attrs[DEVLINK_ATTR_RELOAD_ACTION],				    DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 	if (!devlink_reload_action_is_supported(devlink, action)) {		NL_SET_ERR_MSG(info->extack, "Requested reload action is not supported by the driver");		return -EOPNOTSUPP;	} 	limit = DEVLINK_RELOAD_LIMIT_UNSPEC;	if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) {		struct nla_bitfield32 limits;		u32 limits_selected; 		limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]);		limits_selected = limits.value & limits.selector;		if (!limits_selected) {			NL_SET_ERR_MSG(info->extack, "Invalid limit selected");			return -EINVAL;		}		for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++)			if (limits_selected & BIT(limit))				break;		/* UAPI enables multiselection, but currently it is not used */		if (limits_selected != BIT(limit)) {			NL_SET_ERR_MSG(info->extack, "Multiselection of limit is not supported");			return -EOPNOTSUPP;		}		if (!devlink_reload_limit_is_supported(devlink, limit)) {			NL_SET_ERR_MSG(info->extack, "Requested limit is not supported by the driver");			return -EOPNOTSUPP;		}		if (devlink_reload_combination_is_invalid(action, limit)) {			NL_SET_ERR_MSG(info->extack, "Requested limit is invalid for this action");			return -EINVAL;		}	}	if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||	    info->attrs[DEVLINK_ATTR_NETNS_FD] ||	    info->attrs[DEVLINK_ATTR_NETNS_ID]) {		dest_net = devlink_netns_get(skb, info);		if (IS_ERR(dest_net))			return PTR_ERR(dest_net);		if (!net_eq(dest_net, devlink_net(devlink)) &&		    action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {			NL_SET_ERR_MSG_MOD(info->extack,					   "Changing namespace is only supported for reinit action");			put_net(dest_net);			return -EOPNOTSUPP;		}	} 	err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack); 	if (dest_net)		put_net(dest_net); 	if (err)		return err;	/* For backward compatibility generate reply only if attributes used by user */	if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS])		return 0; 	return devlink_nl_reload_actions_performed_snd(devlink, actions_performed,						       DEVLINK_CMD_RELOAD, info);} bool devlink_reload_actions_valid(const struct devlink_ops *ops){	const struct devlink_reload_combination *comb;	int i; 	if (!devlink_reload_supported(ops)) {		if (WARN_ON(ops->reload_actions))			return false;		return true;	} 	if (WARN_ON(!ops->reload_actions ||		    ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||		    ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX)))		return false; 	if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) ||		    ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX)))		return false; 	for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++)  {		comb = &devlink_reload_invalid_combinations[i];		if (ops->reload_actions == BIT(comb->action) &&		    ops->reload_limits == BIT(comb->limit))			return false;	}	return true;} static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,				   enum devlink_command cmd, u32 portid,				   u32 seq, int flags){	const struct devlink_ops *ops = devlink->ops;	enum devlink_eswitch_encap_mode encap_mode;	u8 inline_mode;	void *hdr;	int err = 0;	u16 mode; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);	if (!hdr)		return -EMSGSIZE; 	err = devlink_nl_put_handle(msg, devlink);	if (err)		goto nla_put_failure; 	if (ops->eswitch_mode_get) {		err = ops->eswitch_mode_get(devlink, &mode);		if (err)			goto nla_put_failure;		err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);		if (err)			goto nla_put_failure;	} 	if (ops->eswitch_inline_mode_get) {		err = ops->eswitch_inline_mode_get(devlink, &inline_mode);		if (err)			goto nla_put_failure;		err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,				 inline_mode);		if (err)			goto nla_put_failure;	} 	if (ops->eswitch_encap_mode_get) {		err = ops->eswitch_encap_mode_get(devlink, &encap_mode);		if (err)			goto nla_put_failure;		err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);		if (err)			goto nla_put_failure;	} 	genlmsg_end(msg, hdr);	return 0; nla_put_failure:	genlmsg_cancel(msg, hdr);	return err;} int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	struct sk_buff *msg;	int err; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,				      info->snd_portid, info->snd_seq, 0); 	if (err) {		nlmsg_free(msg);		return err;	} 	return genlmsg_reply(msg, info);} int devlink_nl_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	const struct devlink_ops *ops = devlink->ops;	enum devlink_eswitch_encap_mode encap_mode;	u8 inline_mode;	int err = 0;	u16 mode; 	if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {		if (!ops->eswitch_mode_set)			return -EOPNOTSUPP;		err = devlink_rates_check(devlink, devlink_rate_is_node,					  info->extack);		if (err)			return err;		mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);		err = ops->eswitch_mode_set(devlink, mode, info->extack);		if (err)			return err;	} 	if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {		if (!ops->eswitch_inline_mode_set)			return -EOPNOTSUPP;		inline_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);		err = ops->eswitch_inline_mode_set(devlink, inline_mode,						   info->extack);		if (err)			return err;	} 	if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {		if (!ops->eswitch_encap_mode_set)			return -EOPNOTSUPP;		encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);		err = ops->eswitch_encap_mode_set(devlink, encap_mode,						  info->extack);		if (err)			return err;	} 	return 0;} int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn){	if (!req->msg)		return 0;	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);}EXPORT_SYMBOL_GPL(devlink_info_serial_number_put); int devlink_info_board_serial_number_put(struct devlink_info_req *req,					 const char *bsn){	if (!req->msg)		return 0;	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,			      bsn);}EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put); static int devlink_info_version_put(struct devlink_info_req *req, int attr,				    const char *version_name,				    const char *version_value,				    enum devlink_info_version_type version_type){	struct nlattr *nest;	int err; 	if (req->version_cb)		req->version_cb(version_name, version_type,				req->version_cb_priv); 	if (!req->msg || !*version_value)		return 0; 	nest = nla_nest_start_noflag(req->msg, attr);	if (!nest)		return -EMSGSIZE; 	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,			     version_name);	if (err)		goto nla_put_failure; 	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,			     version_value);	if (err)		goto nla_put_failure; 	nla_nest_end(req->msg, nest); 	return 0; nla_put_failure:	nla_nest_cancel(req->msg, nest);	return err;} int devlink_info_version_fixed_put(struct devlink_info_req *req,				   const char *version_name,				   const char *version_value){	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,					version_name, version_value,					DEVLINK_INFO_VERSION_TYPE_NONE);}EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put); int devlink_info_version_stored_put(struct devlink_info_req *req,				    const char *version_name,				    const char *version_value){	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,					version_name, version_value,					DEVLINK_INFO_VERSION_TYPE_NONE);}EXPORT_SYMBOL_GPL(devlink_info_version_stored_put); int devlink_info_version_stored_put_ext(struct devlink_info_req *req,					const char *version_name,					const char *version_value,					enum devlink_info_version_type version_type){	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,					version_name, version_value,					version_type);}EXPORT_SYMBOL_GPL(devlink_info_version_stored_put_ext); int devlink_info_version_running_put(struct devlink_info_req *req,				     const char *version_name,				     const char *version_value){	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,					version_name, version_value,					DEVLINK_INFO_VERSION_TYPE_NONE);}EXPORT_SYMBOL_GPL(devlink_info_version_running_put); int devlink_info_version_running_put_ext(struct devlink_info_req *req,					 const char *version_name,					 const char *version_value,					 enum devlink_info_version_type version_type){	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,					version_name, version_value,					version_type);}EXPORT_SYMBOL_GPL(devlink_info_version_running_put_ext); static int devlink_nl_driver_info_get(const struct device_driver *drv,				      struct devlink_info_req *req){	if (!drv)		return 0; 	if (drv->name[0])		return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME,				      drv->name); 	return 0;} static intdevlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,		     enum devlink_command cmd, u32 portid,		     u32 seq, int flags, struct netlink_ext_ack *extack){	struct devlink_info_req req = {};	void *hdr;	int err; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);	if (!hdr)		return -EMSGSIZE; 	err = -EMSGSIZE;	if (devlink_nl_put_handle(msg, devlink))		goto err_cancel_msg; 	req.msg = msg;	if (devlink->ops->info_get) {		err = devlink->ops->info_get(devlink, &req, extack);		if (err)			goto err_cancel_msg;	} 	err = devlink_nl_driver_info_get(devlink->dev_driver, &req);	if (err)		goto err_cancel_msg; 	genlmsg_end(msg, hdr);	return 0; err_cancel_msg:	genlmsg_cancel(msg, hdr);	return err;} int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	struct sk_buff *msg;	int err; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,				   info->snd_portid, info->snd_seq, 0,				   info->extack);	if (err) {		nlmsg_free(msg);		return err;	} 	return genlmsg_reply(msg, info);} static intdevlink_nl_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink,			     struct netlink_callback *cb, int flags){	int err; 	err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,				   NETLINK_CB(cb->skb).portid,				   cb->nlh->nlmsg_seq, flags,				   cb->extack);	if (err == -EOPNOTSUPP)		err = 0;	return err;} int devlink_nl_info_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb){	return devlink_nl_dumpit(msg, cb, devlink_nl_info_get_dump_one);} static int devlink_nl_flash_update_fill(struct sk_buff *msg,					struct devlink *devlink,					enum devlink_command cmd,					struct devlink_flash_notify *params){	void *hdr; 	hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);	if (!hdr)		return -EMSGSIZE; 	if (devlink_nl_put_handle(msg, devlink))		goto nla_put_failure; 	if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)		goto out; 	if (params->status_msg &&	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,			   params->status_msg))		goto nla_put_failure;	if (params->component &&	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,			   params->component))		goto nla_put_failure;	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,			       params->done))		goto nla_put_failure;	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,			       params->total))		goto nla_put_failure;	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,			       params->timeout))		goto nla_put_failure; out:	genlmsg_end(msg, hdr);	return 0; nla_put_failure:	genlmsg_cancel(msg, hdr);	return -EMSGSIZE;} static void __devlink_flash_update_notify(struct devlink *devlink,					  enum devlink_command cmd,					  struct devlink_flash_notify *params){	struct sk_buff *msg;	int err; 	WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&

Lines 501–1000 of 1444. Previous lines