1623cd13bSJakub Kicinski // SPDX-License-Identifier: GPL-2.0-or-later 2623cd13bSJakub Kicinski /* 3623cd13bSJakub Kicinski * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4623cd13bSJakub Kicinski * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 5623cd13bSJakub Kicinski */ 6623cd13bSJakub Kicinski 7623cd13bSJakub Kicinski #include <net/genetlink.h> 807f3af66SJakub Kicinski #include <net/sock.h> 9623cd13bSJakub Kicinski 10623cd13bSJakub Kicinski #include "devl_internal.h" 11623cd13bSJakub Kicinski 12623cd13bSJakub Kicinski static const struct genl_multicast_group devlink_nl_mcgrps[] = { 13623cd13bSJakub Kicinski [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, 14623cd13bSJakub Kicinski }; 15623cd13bSJakub Kicinski 16623cd13bSJakub Kicinski static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 17623cd13bSJakub Kicinski [DEVLINK_ATTR_UNSPEC] = { .strict_start_type = 18623cd13bSJakub Kicinski DEVLINK_ATTR_TRAP_POLICER_ID }, 19623cd13bSJakub Kicinski [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, 20623cd13bSJakub Kicinski [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, 21623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 }, 22623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO, 23623cd13bSJakub Kicinski DEVLINK_PORT_TYPE_IB), 24623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 }, 25623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 }, 26623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 }, 27623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 }, 28623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 }, 29623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 }, 30623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 }, 31623cd13bSJakub Kicinski [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 }, 32623cd13bSJakub Kicinski [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY, 33623cd13bSJakub Kicinski DEVLINK_ESWITCH_MODE_SWITCHDEV), 34623cd13bSJakub Kicinski [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 }, 35623cd13bSJakub Kicinski [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 }, 36623cd13bSJakub Kicinski [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING }, 37623cd13bSJakub Kicinski [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 }, 38623cd13bSJakub Kicinski [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64}, 39623cd13bSJakub Kicinski [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64}, 40623cd13bSJakub Kicinski [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING }, 41623cd13bSJakub Kicinski [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 }, 42623cd13bSJakub Kicinski [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 }, 43623cd13bSJakub Kicinski [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING }, 44623cd13bSJakub Kicinski [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 }, 45623cd13bSJakub Kicinski [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 }, 46623cd13bSJakub Kicinski [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 }, 47623cd13bSJakub Kicinski [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING }, 48623cd13bSJakub Kicinski [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 }, 49623cd13bSJakub Kicinski [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 }, 50623cd13bSJakub Kicinski [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING }, 51623cd13bSJakub Kicinski [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING }, 52623cd13bSJakub Kicinski [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = 53623cd13bSJakub Kicinski NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS), 54623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING }, 55623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 }, 56623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING }, 57623cd13bSJakub Kicinski [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 }, 58623cd13bSJakub Kicinski [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 }, 59623cd13bSJakub Kicinski [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 }, 60623cd13bSJakub Kicinski [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 }, 61623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 }, 62623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 }, 63623cd13bSJakub Kicinski [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 }, 64623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED }, 65623cd13bSJakub Kicinski [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 66623cd13bSJakub Kicinski DEVLINK_RELOAD_ACTION_MAX), 67623cd13bSJakub Kicinski [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), 68623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, 69623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, 70623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, 71623cd13bSJakub Kicinski [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, 72623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 }, 73623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 }, 74623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 }, 75623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING }, 76623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, 77623cd13bSJakub Kicinski [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, 78623cd13bSJakub Kicinski [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING }, 79623cd13bSJakub Kicinski [DEVLINK_ATTR_SELFTESTS] = { .type = NLA_NESTED }, 80623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .type = NLA_U32 }, 81623cd13bSJakub Kicinski [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32 }, 82623cd13bSJakub Kicinski [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG }, 83623cd13bSJakub Kicinski }; 84623cd13bSJakub Kicinski 85870c7ad4SJakub Kicinski struct devlink * 86870c7ad4SJakub Kicinski devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs) 87623cd13bSJakub Kicinski { 88623cd13bSJakub Kicinski struct devlink *devlink; 89623cd13bSJakub Kicinski unsigned long index; 90623cd13bSJakub Kicinski char *busname; 91623cd13bSJakub Kicinski char *devname; 92623cd13bSJakub Kicinski 93623cd13bSJakub Kicinski if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME]) 94623cd13bSJakub Kicinski return ERR_PTR(-EINVAL); 95623cd13bSJakub Kicinski 96623cd13bSJakub Kicinski busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]); 97623cd13bSJakub Kicinski devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); 98623cd13bSJakub Kicinski 99623cd13bSJakub Kicinski devlinks_xa_for_each_registered_get(net, index, devlink) { 100870c7ad4SJakub Kicinski devl_lock(devlink); 101ed539ba6SJakub Kicinski if (devl_is_registered(devlink) && 102ed539ba6SJakub Kicinski strcmp(devlink->dev->bus->name, busname) == 0 && 103623cd13bSJakub Kicinski strcmp(dev_name(devlink->dev), devname) == 0) 104623cd13bSJakub Kicinski return devlink; 105870c7ad4SJakub Kicinski devl_unlock(devlink); 106623cd13bSJakub Kicinski devlink_put(devlink); 107623cd13bSJakub Kicinski } 108623cd13bSJakub Kicinski 109623cd13bSJakub Kicinski return ERR_PTR(-ENODEV); 110623cd13bSJakub Kicinski } 111623cd13bSJakub Kicinski 112*ee6d78acSJiri Pirko static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info, 113*ee6d78acSJiri Pirko u8 flags) 114623cd13bSJakub Kicinski { 115623cd13bSJakub Kicinski struct devlink_port *devlink_port; 116623cd13bSJakub Kicinski struct devlink *devlink; 117623cd13bSJakub Kicinski int err; 118623cd13bSJakub Kicinski 119870c7ad4SJakub Kicinski devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs); 120623cd13bSJakub Kicinski if (IS_ERR(devlink)) 121623cd13bSJakub Kicinski return PTR_ERR(devlink); 122870c7ad4SJakub Kicinski 123623cd13bSJakub Kicinski info->user_ptr[0] = devlink; 124*ee6d78acSJiri Pirko if (flags & DEVLINK_NL_FLAG_NEED_PORT) { 125623cd13bSJakub Kicinski devlink_port = devlink_port_get_from_info(devlink, info); 126623cd13bSJakub Kicinski if (IS_ERR(devlink_port)) { 127623cd13bSJakub Kicinski err = PTR_ERR(devlink_port); 128623cd13bSJakub Kicinski goto unlock; 129623cd13bSJakub Kicinski } 130623cd13bSJakub Kicinski info->user_ptr[1] = devlink_port; 131*ee6d78acSJiri Pirko } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) { 132623cd13bSJakub Kicinski devlink_port = devlink_port_get_from_info(devlink, info); 133623cd13bSJakub Kicinski if (!IS_ERR(devlink_port)) 134623cd13bSJakub Kicinski info->user_ptr[1] = devlink_port; 135623cd13bSJakub Kicinski } 136623cd13bSJakub Kicinski return 0; 137623cd13bSJakub Kicinski 138623cd13bSJakub Kicinski unlock: 139623cd13bSJakub Kicinski devl_unlock(devlink); 140623cd13bSJakub Kicinski devlink_put(devlink); 141623cd13bSJakub Kicinski return err; 142623cd13bSJakub Kicinski } 143623cd13bSJakub Kicinski 144*ee6d78acSJiri Pirko int devlink_nl_pre_doit(const struct genl_split_ops *ops, 145*ee6d78acSJiri Pirko struct sk_buff *skb, struct genl_info *info) 146*ee6d78acSJiri Pirko { 147*ee6d78acSJiri Pirko return __devlink_nl_pre_doit(skb, info, ops->internal_flags); 148*ee6d78acSJiri Pirko } 149*ee6d78acSJiri Pirko 150*ee6d78acSJiri Pirko int devlink_nl_pre_doit_port(const struct genl_split_ops *ops, 151*ee6d78acSJiri Pirko struct sk_buff *skb, struct genl_info *info) 152*ee6d78acSJiri Pirko { 153*ee6d78acSJiri Pirko return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT); 154*ee6d78acSJiri Pirko } 155*ee6d78acSJiri Pirko 156*ee6d78acSJiri Pirko int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, 157*ee6d78acSJiri Pirko struct sk_buff *skb, 158*ee6d78acSJiri Pirko struct genl_info *info) 159*ee6d78acSJiri Pirko { 160*ee6d78acSJiri Pirko return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT); 161*ee6d78acSJiri Pirko } 162*ee6d78acSJiri Pirko 1638300dce5SJiri Pirko void devlink_nl_post_doit(const struct genl_split_ops *ops, 164623cd13bSJakub Kicinski struct sk_buff *skb, struct genl_info *info) 165623cd13bSJakub Kicinski { 166623cd13bSJakub Kicinski struct devlink *devlink; 167623cd13bSJakub Kicinski 168623cd13bSJakub Kicinski devlink = info->user_ptr[0]; 169623cd13bSJakub Kicinski devl_unlock(devlink); 170623cd13bSJakub Kicinski devlink_put(devlink); 171623cd13bSJakub Kicinski } 172623cd13bSJakub Kicinski 1738589ba4eSJiri Pirko static const struct devlink_cmd *devl_cmds[] = { 1748589ba4eSJiri Pirko [DEVLINK_CMD_PORT_GET] = &devl_cmd_port_get, 1758589ba4eSJiri Pirko [DEVLINK_CMD_SB_GET] = &devl_cmd_sb_get, 1768589ba4eSJiri Pirko [DEVLINK_CMD_SB_POOL_GET] = &devl_cmd_sb_pool_get, 1778589ba4eSJiri Pirko [DEVLINK_CMD_SB_PORT_POOL_GET] = &devl_cmd_sb_port_pool_get, 1788589ba4eSJiri Pirko [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_cmd_sb_tc_pool_bind_get, 1798589ba4eSJiri Pirko [DEVLINK_CMD_PARAM_GET] = &devl_cmd_param_get, 1808589ba4eSJiri Pirko [DEVLINK_CMD_REGION_GET] = &devl_cmd_region_get, 1818589ba4eSJiri Pirko [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_cmd_health_reporter_get, 1828589ba4eSJiri Pirko [DEVLINK_CMD_TRAP_GET] = &devl_cmd_trap_get, 1838589ba4eSJiri Pirko [DEVLINK_CMD_TRAP_GROUP_GET] = &devl_cmd_trap_group_get, 1848589ba4eSJiri Pirko [DEVLINK_CMD_TRAP_POLICER_GET] = &devl_cmd_trap_policer_get, 1858589ba4eSJiri Pirko [DEVLINK_CMD_RATE_GET] = &devl_cmd_rate_get, 1868589ba4eSJiri Pirko [DEVLINK_CMD_LINECARD_GET] = &devl_cmd_linecard_get, 1878589ba4eSJiri Pirko [DEVLINK_CMD_SELFTESTS_GET] = &devl_cmd_selftests_get, 18807f3af66SJakub Kicinski }; 18907f3af66SJakub Kicinski 190491a2487SJiri Pirko int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, 191491a2487SJiri Pirko devlink_nl_dump_one_func_t *dump_one) 19207f3af66SJakub Kicinski { 19307f3af66SJakub Kicinski struct devlink_nl_dump_state *state = devlink_dump_state(cb); 19407f3af66SJakub Kicinski struct devlink *devlink; 19507f3af66SJakub Kicinski int err = 0; 19607f3af66SJakub Kicinski 197543753d9SJiri Pirko while ((devlink = devlinks_xa_find_get(sock_net(msg->sk), 198543753d9SJiri Pirko &state->instance))) { 19907f3af66SJakub Kicinski devl_lock(devlink); 200ed539ba6SJakub Kicinski 201ed539ba6SJakub Kicinski if (devl_is_registered(devlink)) 202491a2487SJiri Pirko err = dump_one(msg, devlink, cb); 203ed539ba6SJakub Kicinski else 204ed539ba6SJakub Kicinski err = 0; 205ed539ba6SJakub Kicinski 20607f3af66SJakub Kicinski devl_unlock(devlink); 20707f3af66SJakub Kicinski devlink_put(devlink); 20807f3af66SJakub Kicinski 20907f3af66SJakub Kicinski if (err) 21007f3af66SJakub Kicinski break; 21107f3af66SJakub Kicinski 212543753d9SJiri Pirko state->instance++; 213543753d9SJiri Pirko 21407f3af66SJakub Kicinski /* restart sub-object walk for the next instance */ 21507f3af66SJakub Kicinski state->idx = 0; 21607f3af66SJakub Kicinski } 21707f3af66SJakub Kicinski 21807f3af66SJakub Kicinski if (err != -EMSGSIZE) 21907f3af66SJakub Kicinski return err; 22007f3af66SJakub Kicinski return msg->len; 22107f3af66SJakub Kicinski } 22207f3af66SJakub Kicinski 223491a2487SJiri Pirko int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, 224491a2487SJiri Pirko struct netlink_callback *cb) 225491a2487SJiri Pirko { 226491a2487SJiri Pirko const struct genl_dumpit_info *info = genl_dumpit_info(cb); 227491a2487SJiri Pirko const struct devlink_cmd *cmd = devl_cmds[info->op.cmd]; 228491a2487SJiri Pirko 229491a2487SJiri Pirko return devlink_nl_dumpit(msg, cb, cmd->dump_one); 230491a2487SJiri Pirko } 231491a2487SJiri Pirko 232623cd13bSJakub Kicinski struct genl_family devlink_nl_family __ro_after_init = { 233623cd13bSJakub Kicinski .name = DEVLINK_GENL_NAME, 234623cd13bSJakub Kicinski .version = DEVLINK_GENL_VERSION, 235623cd13bSJakub Kicinski .maxattr = DEVLINK_ATTR_MAX, 236623cd13bSJakub Kicinski .policy = devlink_nl_policy, 237623cd13bSJakub Kicinski .netnsok = true, 238623cd13bSJakub Kicinski .parallel_ops = true, 239623cd13bSJakub Kicinski .pre_doit = devlink_nl_pre_doit, 240623cd13bSJakub Kicinski .post_doit = devlink_nl_post_doit, 241623cd13bSJakub Kicinski .module = THIS_MODULE, 242ba0f66c9SJiri Pirko .small_ops = devlink_nl_small_ops, 243ba0f66c9SJiri Pirko .n_small_ops = ARRAY_SIZE(devlink_nl_small_ops), 2446e067d0cSJiri Pirko .split_ops = devlink_nl_ops, 2456e067d0cSJiri Pirko .n_split_ops = ARRAY_SIZE(devlink_nl_ops), 246623cd13bSJakub Kicinski .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1, 247623cd13bSJakub Kicinski .mcgrps = devlink_nl_mcgrps, 248623cd13bSJakub Kicinski .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps), 249623cd13bSJakub Kicinski }; 250