995 lines · 24.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) 2016 Mellanox Technologies. All rights reserved. * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> */ #include "devl_internal.h" struct devlink_sb {	struct list_head list;	unsigned int index;	u32 size;	u16 ingress_pools_count;	u16 egress_pools_count;	u16 ingress_tc_count;	u16 egress_tc_count;}; static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb){	return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;} static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,						  unsigned int sb_index){	struct devlink_sb *devlink_sb; 	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {		if (devlink_sb->index == sb_index)			return devlink_sb;	}	return NULL;} static bool devlink_sb_index_exists(struct devlink *devlink,				    unsigned int sb_index){	return devlink_sb_get_by_index(devlink, sb_index);} static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,						    struct nlattr **attrs){	if (attrs[DEVLINK_ATTR_SB_INDEX]) {		u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);		struct devlink_sb *devlink_sb; 		devlink_sb = devlink_sb_get_by_index(devlink, sb_index);		if (!devlink_sb)			return ERR_PTR(-ENODEV);		return devlink_sb;	}	return ERR_PTR(-EINVAL);} static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,						   struct genl_info *info){	return devlink_sb_get_from_attrs(devlink, info->attrs);} static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,						struct nlattr **attrs,						u16 *p_pool_index){	u16 val; 	if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])		return -EINVAL; 	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);	if (val >= devlink_sb_pool_count(devlink_sb))		return -EINVAL;	*p_pool_index = val;	return 0;} static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,					       struct genl_info *info,					       u16 *p_pool_index){	return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,						    p_pool_index);} static intdevlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,				    enum devlink_sb_pool_type *p_pool_type){	u8 val; 	if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])		return -EINVAL; 	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);	if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&	    val != DEVLINK_SB_POOL_TYPE_EGRESS)		return -EINVAL;	*p_pool_type = val;	return 0;} static intdevlink_sb_pool_type_get_from_info(struct genl_info *info,				   enum devlink_sb_pool_type *p_pool_type){	return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);} static intdevlink_sb_th_type_get_from_attrs(struct nlattr **attrs,				  enum devlink_sb_threshold_type *p_th_type){	u8 val; 	if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])		return -EINVAL; 	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);	if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&	    val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)		return -EINVAL;	*p_th_type = val;	return 0;} static intdevlink_sb_th_type_get_from_info(struct genl_info *info,				 enum devlink_sb_threshold_type *p_th_type){	return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);} static intdevlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,				   struct nlattr **attrs,				   enum devlink_sb_pool_type pool_type,				   u16 *p_tc_index){	u16 val; 	if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])		return -EINVAL; 	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);	if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&	    val >= devlink_sb->ingress_tc_count)		return -EINVAL;	if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&	    val >= devlink_sb->egress_tc_count)		return -EINVAL;	*p_tc_index = val;	return 0;} static intdevlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,				  struct genl_info *info,				  enum devlink_sb_pool_type pool_type,				  u16 *p_tc_index){	return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,						  pool_type, p_tc_index);} static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,			      struct devlink_sb *devlink_sb,			      enum devlink_command cmd, u32 portid,			      u32 seq, int flags){	void *hdr; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);	if (!hdr)		return -EMSGSIZE; 	if (devlink_nl_put_handle(msg, devlink))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,			devlink_sb->ingress_pools_count))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,			devlink_sb->egress_pools_count))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,			devlink_sb->ingress_tc_count))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,			devlink_sb->egress_tc_count))		goto nla_put_failure; 	genlmsg_end(msg, hdr);	return 0; nla_put_failure:	genlmsg_cancel(msg, hdr);	return -EMSGSIZE;} int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	struct devlink_sb *devlink_sb;	struct sk_buff *msg;	int err; 	devlink_sb = devlink_sb_get_from_info(devlink, info);	if (IS_ERR(devlink_sb))		return PTR_ERR(devlink_sb); 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = devlink_nl_sb_fill(msg, devlink, devlink_sb,				 DEVLINK_CMD_SB_NEW,				 info->snd_portid, info->snd_seq, 0);	if (err) {		nlmsg_free(msg);		return err;	} 	return genlmsg_reply(msg, info);} static intdevlink_nl_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink,			   struct netlink_callback *cb, int flags){	struct devlink_nl_dump_state *state = devlink_dump_state(cb);	struct devlink_sb *devlink_sb;	int idx = 0;	int err = 0; 	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {		if (idx < state->idx) {			idx++;			continue;		}		err = devlink_nl_sb_fill(msg, devlink, devlink_sb,					 DEVLINK_CMD_SB_NEW,					 NETLINK_CB(cb->skb).portid,					 cb->nlh->nlmsg_seq, flags);		if (err) {			state->idx = idx;			break;		}		idx++;	} 	return err;} int devlink_nl_sb_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb){	return devlink_nl_dumpit(skb, cb, devlink_nl_sb_get_dump_one);} static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,				   struct devlink_sb *devlink_sb,				   u16 pool_index, enum devlink_command cmd,				   u32 portid, u32 seq, int flags){	struct devlink_sb_pool_info pool_info;	void *hdr;	int err; 	err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,					pool_index, &pool_info);	if (err)		return err; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);	if (!hdr)		return -EMSGSIZE; 	if (devlink_nl_put_handle(msg, devlink))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))		goto nla_put_failure;	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))		goto nla_put_failure;	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,		       pool_info.threshold_type))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,			pool_info.cell_size))		goto nla_put_failure; 	genlmsg_end(msg, hdr);	return 0; nla_put_failure:	genlmsg_cancel(msg, hdr);	return -EMSGSIZE;} int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	struct devlink_sb *devlink_sb;	struct sk_buff *msg;	u16 pool_index;	int err; 	devlink_sb = devlink_sb_get_from_info(devlink, info);	if (IS_ERR(devlink_sb))		return PTR_ERR(devlink_sb); 	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,						  &pool_index);	if (err)		return err; 	if (!devlink->ops->sb_pool_get)		return -EOPNOTSUPP; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,				      DEVLINK_CMD_SB_POOL_NEW,				      info->snd_portid, info->snd_seq, 0);	if (err) {		nlmsg_free(msg);		return err;	} 	return genlmsg_reply(msg, info);} static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,				struct devlink *devlink,				struct devlink_sb *devlink_sb,				u32 portid, u32 seq, int flags){	u16 pool_count = devlink_sb_pool_count(devlink_sb);	u16 pool_index;	int err; 	for (pool_index = 0; pool_index < pool_count; pool_index++) {		if (*p_idx < start) {			(*p_idx)++;			continue;		}		err = devlink_nl_sb_pool_fill(msg, devlink,					      devlink_sb,					      pool_index,					      DEVLINK_CMD_SB_POOL_NEW,					      portid, seq, flags);		if (err)			return err;		(*p_idx)++;	}	return 0;} static intdevlink_nl_sb_pool_get_dump_one(struct sk_buff *msg, struct devlink *devlink,				struct netlink_callback *cb, int flags){	struct devlink_nl_dump_state *state = devlink_dump_state(cb);	struct devlink_sb *devlink_sb;	int err = 0;	int idx = 0; 	if (!devlink->ops->sb_pool_get)		return 0; 	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {		err = __sb_pool_get_dumpit(msg, state->idx, &idx,					   devlink, devlink_sb,					   NETLINK_CB(cb->skb).portid,					   cb->nlh->nlmsg_seq, flags);		if (err == -EOPNOTSUPP) {			err = 0;		} else if (err) {			state->idx = idx;			break;		}	} 	return err;} int devlink_nl_sb_pool_get_dumpit(struct sk_buff *skb,				  struct netlink_callback *cb){	return devlink_nl_dumpit(skb, cb, devlink_nl_sb_pool_get_dump_one);} static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,			       u16 pool_index, u32 size,			       enum devlink_sb_threshold_type threshold_type,			       struct netlink_ext_ack *extack) {	const struct devlink_ops *ops = devlink->ops; 	if (ops->sb_pool_set)		return ops->sb_pool_set(devlink, sb_index, pool_index,					size, threshold_type, extack);	return -EOPNOTSUPP;} int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	enum devlink_sb_threshold_type threshold_type;	struct devlink_sb *devlink_sb;	u16 pool_index;	u32 size;	int err; 	devlink_sb = devlink_sb_get_from_info(devlink, info);	if (IS_ERR(devlink_sb))		return PTR_ERR(devlink_sb); 	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,						  &pool_index);	if (err)		return err; 	err = devlink_sb_th_type_get_from_info(info, &threshold_type);	if (err)		return err; 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_POOL_SIZE))		return -EINVAL; 	size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);	return devlink_sb_pool_set(devlink, devlink_sb->index,				   pool_index, size, threshold_type,				   info->extack);} static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,					struct devlink *devlink,					struct devlink_port *devlink_port,					struct devlink_sb *devlink_sb,					u16 pool_index,					enum devlink_command cmd,					u32 portid, u32 seq, int flags){	const struct devlink_ops *ops = devlink->ops;	u32 threshold;	void *hdr;	int err; 	err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,				    pool_index, &threshold);	if (err)		return err; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);	if (!hdr)		return -EMSGSIZE; 	if (devlink_nl_put_handle(msg, devlink))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))		goto nla_put_failure;	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))		goto nla_put_failure;	if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))		goto nla_put_failure; 	if (ops->sb_occ_port_pool_get) {		u32 cur;		u32 max; 		err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,						pool_index, &cur, &max);		if (err && err != -EOPNOTSUPP)			goto sb_occ_get_failure;		if (!err) {			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))				goto nla_put_failure;			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))				goto nla_put_failure;		}	} 	genlmsg_end(msg, hdr);	return 0; nla_put_failure:	err = -EMSGSIZE;

Lines 1–500 of 995.