18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/core/devlink.c - Network physical/parent device Netlink interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Heavily inspired by net/wireless/ 68c2ecf20Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 78c2ecf20Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/gfp.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci#include <linux/list.h> 178c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 198c2ecf20Sopenharmony_ci#include <linux/refcount.h> 208c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 218c2ecf20Sopenharmony_ci#include <linux/u64_stats_sync.h> 228c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 238c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 248c2ecf20Sopenharmony_ci#include <net/netlink.h> 258c2ecf20Sopenharmony_ci#include <net/genetlink.h> 268c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 278c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 288c2ecf20Sopenharmony_ci#include <net/sock.h> 298c2ecf20Sopenharmony_ci#include <net/devlink.h> 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include <trace/events/devlink.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = { 348c2ecf20Sopenharmony_ci { 358c2ecf20Sopenharmony_ci .name = "destination mac", 368c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC, 378c2ecf20Sopenharmony_ci .bitwidth = 48, 388c2ecf20Sopenharmony_ci }, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ethernet = { 428c2ecf20Sopenharmony_ci .name = "ethernet", 438c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_HEADER_ETHERNET, 448c2ecf20Sopenharmony_ci .fields = devlink_dpipe_fields_ethernet, 458c2ecf20Sopenharmony_ci .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet), 468c2ecf20Sopenharmony_ci .global = true, 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ethernet); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = { 518c2ecf20Sopenharmony_ci { 528c2ecf20Sopenharmony_ci .name = "destination ip", 538c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP, 548c2ecf20Sopenharmony_ci .bitwidth = 32, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ipv4 = { 598c2ecf20Sopenharmony_ci .name = "ipv4", 608c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_HEADER_IPV4, 618c2ecf20Sopenharmony_ci .fields = devlink_dpipe_fields_ipv4, 628c2ecf20Sopenharmony_ci .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4), 638c2ecf20Sopenharmony_ci .global = true, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ipv4); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = { 688c2ecf20Sopenharmony_ci { 698c2ecf20Sopenharmony_ci .name = "destination ip", 708c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP, 718c2ecf20Sopenharmony_ci .bitwidth = 128, 728c2ecf20Sopenharmony_ci }, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ipv6 = { 768c2ecf20Sopenharmony_ci .name = "ipv6", 778c2ecf20Sopenharmony_ci .id = DEVLINK_DPIPE_HEADER_IPV6, 788c2ecf20Sopenharmony_ci .fields = devlink_dpipe_fields_ipv6, 798c2ecf20Sopenharmony_ci .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6), 808c2ecf20Sopenharmony_ci .global = true, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ipv6); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg); 858c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr); 868c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = { 898c2ecf20Sopenharmony_ci [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY }, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic LIST_HEAD(devlink_list); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* devlink_mutex 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * An overall lock guarding every operation coming from userspace. 978c2ecf20Sopenharmony_ci * It also guards devlink devices list and it is taken when 988c2ecf20Sopenharmony_ci * driver registers/unregisters it. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(devlink_mutex); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct net *devlink_net(const struct devlink *devlink) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return read_pnet(&devlink->_net); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_net); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void __devlink_net_set(struct devlink *devlink, struct net *net) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci write_pnet(&devlink->_net, net); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_civoid devlink_net_set(struct devlink *devlink, struct net *net) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci if (WARN_ON(devlink->registered)) 1168c2ecf20Sopenharmony_ci return; 1178c2ecf20Sopenharmony_ci __devlink_net_set(devlink, net); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_net_set); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct devlink *devlink_get_from_attrs(struct net *net, 1228c2ecf20Sopenharmony_ci struct nlattr **attrs) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct devlink *devlink; 1258c2ecf20Sopenharmony_ci char *busname; 1268c2ecf20Sopenharmony_ci char *devname; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME]) 1298c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]); 1328c2ecf20Sopenharmony_ci devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink_mutex); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 1378c2ecf20Sopenharmony_ci if (strcmp(devlink->dev->bus->name, busname) == 0 && 1388c2ecf20Sopenharmony_ci strcmp(dev_name(devlink->dev), devname) == 0 && 1398c2ecf20Sopenharmony_ci net_eq(devlink_net(devlink), net)) 1408c2ecf20Sopenharmony_ci return devlink; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic struct devlink *devlink_get_from_info(struct genl_info *info) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return devlink_get_from_attrs(genl_info_net(info), info->attrs); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_by_index(struct devlink *devlink, 1528c2ecf20Sopenharmony_ci unsigned int port_index) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci list_for_each_entry(devlink_port, &devlink->port_list, list) { 1578c2ecf20Sopenharmony_ci if (devlink_port->index == port_index) 1588c2ecf20Sopenharmony_ci return devlink_port; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci return NULL; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic bool devlink_port_index_exists(struct devlink *devlink, 1648c2ecf20Sopenharmony_ci unsigned int port_index) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci return devlink_port_get_by_index(devlink, port_index); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink, 1708c2ecf20Sopenharmony_ci struct nlattr **attrs) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_PORT_INDEX]) { 1738c2ecf20Sopenharmony_ci u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]); 1748c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci devlink_port = devlink_port_get_by_index(devlink, port_index); 1778c2ecf20Sopenharmony_ci if (!devlink_port) 1788c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 1798c2ecf20Sopenharmony_ci return devlink_port; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, 1858c2ecf20Sopenharmony_ci struct genl_info *info) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci return devlink_port_get_from_attrs(devlink, info->attrs); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistruct devlink_sb { 1918c2ecf20Sopenharmony_ci struct list_head list; 1928c2ecf20Sopenharmony_ci unsigned int index; 1938c2ecf20Sopenharmony_ci u32 size; 1948c2ecf20Sopenharmony_ci u16 ingress_pools_count; 1958c2ecf20Sopenharmony_ci u16 egress_pools_count; 1968c2ecf20Sopenharmony_ci u16 ingress_tc_count; 1978c2ecf20Sopenharmony_ci u16 egress_tc_count; 1988c2ecf20Sopenharmony_ci}; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink, 2068c2ecf20Sopenharmony_ci unsigned int sb_index) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 2118c2ecf20Sopenharmony_ci if (devlink_sb->index == sb_index) 2128c2ecf20Sopenharmony_ci return devlink_sb; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci return NULL; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic bool devlink_sb_index_exists(struct devlink *devlink, 2188c2ecf20Sopenharmony_ci unsigned int sb_index) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return devlink_sb_get_by_index(devlink, sb_index); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink, 2248c2ecf20Sopenharmony_ci struct nlattr **attrs) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_SB_INDEX]) { 2278c2ecf20Sopenharmony_ci u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]); 2288c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_by_index(devlink, sb_index); 2318c2ecf20Sopenharmony_ci if (!devlink_sb) 2328c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 2338c2ecf20Sopenharmony_ci return devlink_sb; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink, 2398c2ecf20Sopenharmony_ci struct genl_info *info) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return devlink_sb_get_from_attrs(devlink, info->attrs); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb, 2458c2ecf20Sopenharmony_ci struct nlattr **attrs, 2468c2ecf20Sopenharmony_ci u16 *p_pool_index) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci u16 val; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX]) 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]); 2548c2ecf20Sopenharmony_ci if (val >= devlink_sb_pool_count(devlink_sb)) 2558c2ecf20Sopenharmony_ci return -EINVAL; 2568c2ecf20Sopenharmony_ci *p_pool_index = val; 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb, 2618c2ecf20Sopenharmony_ci struct genl_info *info, 2628c2ecf20Sopenharmony_ci u16 *p_pool_index) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs, 2658c2ecf20Sopenharmony_ci p_pool_index); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int 2698c2ecf20Sopenharmony_cidevlink_sb_pool_type_get_from_attrs(struct nlattr **attrs, 2708c2ecf20Sopenharmony_ci enum devlink_sb_pool_type *p_pool_type) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci u8 val; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE]) 2758c2ecf20Sopenharmony_ci return -EINVAL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]); 2788c2ecf20Sopenharmony_ci if (val != DEVLINK_SB_POOL_TYPE_INGRESS && 2798c2ecf20Sopenharmony_ci val != DEVLINK_SB_POOL_TYPE_EGRESS) 2808c2ecf20Sopenharmony_ci return -EINVAL; 2818c2ecf20Sopenharmony_ci *p_pool_type = val; 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int 2868c2ecf20Sopenharmony_cidevlink_sb_pool_type_get_from_info(struct genl_info *info, 2878c2ecf20Sopenharmony_ci enum devlink_sb_pool_type *p_pool_type) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int 2938c2ecf20Sopenharmony_cidevlink_sb_th_type_get_from_attrs(struct nlattr **attrs, 2948c2ecf20Sopenharmony_ci enum devlink_sb_threshold_type *p_th_type) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci u8 val; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]); 3028c2ecf20Sopenharmony_ci if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC && 3038c2ecf20Sopenharmony_ci val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC) 3048c2ecf20Sopenharmony_ci return -EINVAL; 3058c2ecf20Sopenharmony_ci *p_th_type = val; 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int 3108c2ecf20Sopenharmony_cidevlink_sb_th_type_get_from_info(struct genl_info *info, 3118c2ecf20Sopenharmony_ci enum devlink_sb_threshold_type *p_th_type) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int 3178c2ecf20Sopenharmony_cidevlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb, 3188c2ecf20Sopenharmony_ci struct nlattr **attrs, 3198c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type, 3208c2ecf20Sopenharmony_ci u16 *p_tc_index) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u16 val; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_SB_TC_INDEX]) 3258c2ecf20Sopenharmony_ci return -EINVAL; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]); 3288c2ecf20Sopenharmony_ci if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS && 3298c2ecf20Sopenharmony_ci val >= devlink_sb->ingress_tc_count) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS && 3328c2ecf20Sopenharmony_ci val >= devlink_sb->egress_tc_count) 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci *p_tc_index = val; 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int 3398c2ecf20Sopenharmony_cidevlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb, 3408c2ecf20Sopenharmony_ci struct genl_info *info, 3418c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type, 3428c2ecf20Sopenharmony_ci u16 *p_tc_index) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs, 3458c2ecf20Sopenharmony_ci pool_type, p_tc_index); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistruct devlink_region { 3498c2ecf20Sopenharmony_ci struct devlink *devlink; 3508c2ecf20Sopenharmony_ci struct devlink_port *port; 3518c2ecf20Sopenharmony_ci struct list_head list; 3528c2ecf20Sopenharmony_ci union { 3538c2ecf20Sopenharmony_ci const struct devlink_region_ops *ops; 3548c2ecf20Sopenharmony_ci const struct devlink_port_region_ops *port_ops; 3558c2ecf20Sopenharmony_ci }; 3568c2ecf20Sopenharmony_ci struct list_head snapshot_list; 3578c2ecf20Sopenharmony_ci u32 max_snapshots; 3588c2ecf20Sopenharmony_ci u32 cur_snapshots; 3598c2ecf20Sopenharmony_ci u64 size; 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistruct devlink_snapshot { 3638c2ecf20Sopenharmony_ci struct list_head list; 3648c2ecf20Sopenharmony_ci struct devlink_region *region; 3658c2ecf20Sopenharmony_ci u8 *data; 3668c2ecf20Sopenharmony_ci u32 id; 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic struct devlink_region * 3708c2ecf20Sopenharmony_cidevlink_region_get_by_name(struct devlink *devlink, const char *region_name) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct devlink_region *region; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci list_for_each_entry(region, &devlink->region_list, list) 3758c2ecf20Sopenharmony_ci if (!strcmp(region->ops->name, region_name)) 3768c2ecf20Sopenharmony_ci return region; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return NULL; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic struct devlink_region * 3828c2ecf20Sopenharmony_cidevlink_port_region_get_by_name(struct devlink_port *port, 3838c2ecf20Sopenharmony_ci const char *region_name) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct devlink_region *region; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci list_for_each_entry(region, &port->region_list, list) 3888c2ecf20Sopenharmony_ci if (!strcmp(region->ops->name, region_name)) 3898c2ecf20Sopenharmony_ci return region; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return NULL; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic struct devlink_snapshot * 3958c2ecf20Sopenharmony_cidevlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci list_for_each_entry(snapshot, ®ion->snapshot_list, list) 4008c2ecf20Sopenharmony_ci if (snapshot->id == id) 4018c2ecf20Sopenharmony_ci return snapshot; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return NULL; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_PORT BIT(0) 4078c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* The per devlink instance lock is taken by default in the pre-doit 4108c2ecf20Sopenharmony_ci * operation, yet several commands do not require this. The global 4118c2ecf20Sopenharmony_ci * devlink lock is taken and protects from disruption by user-calls. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NO_LOCK BIT(2) 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int devlink_nl_pre_doit(const struct genl_ops *ops, 4168c2ecf20Sopenharmony_ci struct sk_buff *skb, struct genl_info *info) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 4198c2ecf20Sopenharmony_ci struct devlink *devlink; 4208c2ecf20Sopenharmony_ci int err; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 4238c2ecf20Sopenharmony_ci devlink = devlink_get_from_info(info); 4248c2ecf20Sopenharmony_ci if (IS_ERR(devlink)) { 4258c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 4268c2ecf20Sopenharmony_ci return PTR_ERR(devlink); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) 4298c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 4308c2ecf20Sopenharmony_ci info->user_ptr[0] = devlink; 4318c2ecf20Sopenharmony_ci if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) { 4328c2ecf20Sopenharmony_ci devlink_port = devlink_port_get_from_info(devlink, info); 4338c2ecf20Sopenharmony_ci if (IS_ERR(devlink_port)) { 4348c2ecf20Sopenharmony_ci err = PTR_ERR(devlink_port); 4358c2ecf20Sopenharmony_ci goto unlock; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci info->user_ptr[1] = devlink_port; 4388c2ecf20Sopenharmony_ci } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) { 4398c2ecf20Sopenharmony_ci devlink_port = devlink_port_get_from_info(devlink, info); 4408c2ecf20Sopenharmony_ci if (!IS_ERR(devlink_port)) 4418c2ecf20Sopenharmony_ci info->user_ptr[1] = devlink_port; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciunlock: 4468c2ecf20Sopenharmony_ci if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) 4478c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 4488c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void devlink_nl_post_doit(const struct genl_ops *ops, 4538c2ecf20Sopenharmony_ci struct sk_buff *skb, struct genl_info *info) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct devlink *devlink; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci devlink = info->user_ptr[0]; 4588c2ecf20Sopenharmony_ci if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) 4598c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 4608c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic struct genl_family devlink_nl_family; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cienum devlink_multicast_groups { 4668c2ecf20Sopenharmony_ci DEVLINK_MCGRP_CONFIG, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic const struct genl_multicast_group devlink_nl_mcgrps[] = { 4708c2ecf20Sopenharmony_ci [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name)) 4768c2ecf20Sopenharmony_ci return -EMSGSIZE; 4778c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev))) 4788c2ecf20Sopenharmony_ci return -EMSGSIZE; 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistruct devlink_reload_combination { 4838c2ecf20Sopenharmony_ci enum devlink_reload_action action; 4848c2ecf20Sopenharmony_ci enum devlink_reload_limit limit; 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic const struct devlink_reload_combination devlink_reload_invalid_combinations[] = { 4888c2ecf20Sopenharmony_ci { 4898c2ecf20Sopenharmony_ci /* can't reinitialize driver with no down time */ 4908c2ecf20Sopenharmony_ci .action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 4918c2ecf20Sopenharmony_ci .limit = DEVLINK_RELOAD_LIMIT_NO_RESET, 4928c2ecf20Sopenharmony_ci }, 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic bool 4968c2ecf20Sopenharmony_cidevlink_reload_combination_is_invalid(enum devlink_reload_action action, 4978c2ecf20Sopenharmony_ci enum devlink_reload_limit limit) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci int i; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) 5028c2ecf20Sopenharmony_ci if (devlink_reload_invalid_combinations[i].action == action && 5038c2ecf20Sopenharmony_ci devlink_reload_invalid_combinations[i].limit == limit) 5048c2ecf20Sopenharmony_ci return true; 5058c2ecf20Sopenharmony_ci return false; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic bool 5098c2ecf20Sopenharmony_cidevlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci return test_bit(action, &devlink->ops->reload_actions); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic bool 5158c2ecf20Sopenharmony_cidevlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci return test_bit(limit, &devlink->ops->reload_limits); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int devlink_reload_stat_put(struct sk_buff *msg, 5218c2ecf20Sopenharmony_ci enum devlink_reload_limit limit, u32 value) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct nlattr *reload_stats_entry; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY); 5268c2ecf20Sopenharmony_ci if (!reload_stats_entry) 5278c2ecf20Sopenharmony_ci return -EMSGSIZE; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) || 5308c2ecf20Sopenharmony_ci nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value)) 5318c2ecf20Sopenharmony_ci goto nla_put_failure; 5328c2ecf20Sopenharmony_ci nla_nest_end(msg, reload_stats_entry); 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cinla_put_failure: 5368c2ecf20Sopenharmony_ci nla_nest_cancel(msg, reload_stats_entry); 5378c2ecf20Sopenharmony_ci return -EMSGSIZE; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct nlattr *reload_stats_attr, *act_info, *act_stats; 5438c2ecf20Sopenharmony_ci int i, j, stat_idx; 5448c2ecf20Sopenharmony_ci u32 value; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (!is_remote) 5478c2ecf20Sopenharmony_ci reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS); 5488c2ecf20Sopenharmony_ci else 5498c2ecf20Sopenharmony_ci reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_REMOTE_RELOAD_STATS); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!reload_stats_attr) 5528c2ecf20Sopenharmony_ci return -EMSGSIZE; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { 5558c2ecf20Sopenharmony_ci if ((!is_remote && 5568c2ecf20Sopenharmony_ci !devlink_reload_action_is_supported(devlink, i)) || 5578c2ecf20Sopenharmony_ci i == DEVLINK_RELOAD_ACTION_UNSPEC) 5588c2ecf20Sopenharmony_ci continue; 5598c2ecf20Sopenharmony_ci act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO); 5608c2ecf20Sopenharmony_ci if (!act_info) 5618c2ecf20Sopenharmony_ci goto nla_put_failure; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i)) 5648c2ecf20Sopenharmony_ci goto action_info_nest_cancel; 5658c2ecf20Sopenharmony_ci act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS); 5668c2ecf20Sopenharmony_ci if (!act_stats) 5678c2ecf20Sopenharmony_ci goto action_info_nest_cancel; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { 5708c2ecf20Sopenharmony_ci /* Remote stats are shown even if not locally supported. 5718c2ecf20Sopenharmony_ci * Stats of actions with unspecified limit are shown 5728c2ecf20Sopenharmony_ci * though drivers don't need to register unspecified 5738c2ecf20Sopenharmony_ci * limit. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && 5768c2ecf20Sopenharmony_ci !devlink_reload_limit_is_supported(devlink, j)) || 5778c2ecf20Sopenharmony_ci devlink_reload_combination_is_invalid(i, j)) 5788c2ecf20Sopenharmony_ci continue; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i; 5818c2ecf20Sopenharmony_ci if (!is_remote) 5828c2ecf20Sopenharmony_ci value = devlink->stats.reload_stats[stat_idx]; 5838c2ecf20Sopenharmony_ci else 5848c2ecf20Sopenharmony_ci value = devlink->stats.remote_reload_stats[stat_idx]; 5858c2ecf20Sopenharmony_ci if (devlink_reload_stat_put(msg, j, value)) 5868c2ecf20Sopenharmony_ci goto action_stats_nest_cancel; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci nla_nest_end(msg, act_stats); 5898c2ecf20Sopenharmony_ci nla_nest_end(msg, act_info); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci nla_nest_end(msg, reload_stats_attr); 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ciaction_stats_nest_cancel: 5958c2ecf20Sopenharmony_ci nla_nest_cancel(msg, act_stats); 5968c2ecf20Sopenharmony_ciaction_info_nest_cancel: 5978c2ecf20Sopenharmony_ci nla_nest_cancel(msg, act_info); 5988c2ecf20Sopenharmony_cinla_put_failure: 5998c2ecf20Sopenharmony_ci nla_nest_cancel(msg, reload_stats_attr); 6008c2ecf20Sopenharmony_ci return -EMSGSIZE; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, 6048c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 6058c2ecf20Sopenharmony_ci u32 seq, int flags) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct nlattr *dev_stats; 6088c2ecf20Sopenharmony_ci void *hdr; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 6118c2ecf20Sopenharmony_ci if (!hdr) 6128c2ecf20Sopenharmony_ci return -EMSGSIZE; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 6158c2ecf20Sopenharmony_ci goto nla_put_failure; 6168c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed)) 6178c2ecf20Sopenharmony_ci goto nla_put_failure; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS); 6208c2ecf20Sopenharmony_ci if (!dev_stats) 6218c2ecf20Sopenharmony_ci goto nla_put_failure; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (devlink_reload_stats_put(msg, devlink, false)) 6248c2ecf20Sopenharmony_ci goto dev_stats_nest_cancel; 6258c2ecf20Sopenharmony_ci if (devlink_reload_stats_put(msg, devlink, true)) 6268c2ecf20Sopenharmony_ci goto dev_stats_nest_cancel; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci nla_nest_end(msg, dev_stats); 6298c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cidev_stats_nest_cancel: 6338c2ecf20Sopenharmony_ci nla_nest_cancel(msg, dev_stats); 6348c2ecf20Sopenharmony_cinla_put_failure: 6358c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 6368c2ecf20Sopenharmony_ci return -EMSGSIZE; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic void devlink_notify(struct devlink *devlink, enum devlink_command cmd) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct sk_buff *msg; 6428c2ecf20Sopenharmony_ci int err; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 6478c2ecf20Sopenharmony_ci if (!msg) 6488c2ecf20Sopenharmony_ci return; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0); 6518c2ecf20Sopenharmony_ci if (err) { 6528c2ecf20Sopenharmony_ci nlmsg_free(msg); 6538c2ecf20Sopenharmony_ci return; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 6578c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int devlink_nl_port_attrs_put(struct sk_buff *msg, 6618c2ecf20Sopenharmony_ci struct devlink_port *devlink_port) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs = &devlink_port->attrs; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!devlink_port->attrs_set) 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci if (attrs->lanes) { 6688c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes)) 6698c2ecf20Sopenharmony_ci return -EMSGSIZE; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable)) 6728c2ecf20Sopenharmony_ci return -EMSGSIZE; 6738c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour)) 6748c2ecf20Sopenharmony_ci return -EMSGSIZE; 6758c2ecf20Sopenharmony_ci switch (devlink_port->attrs.flavour) { 6768c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PCI_PF: 6778c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, 6788c2ecf20Sopenharmony_ci attrs->pci_pf.controller) || 6798c2ecf20Sopenharmony_ci nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf)) 6808c2ecf20Sopenharmony_ci return -EMSGSIZE; 6818c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external)) 6828c2ecf20Sopenharmony_ci return -EMSGSIZE; 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PCI_VF: 6858c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, 6868c2ecf20Sopenharmony_ci attrs->pci_vf.controller) || 6878c2ecf20Sopenharmony_ci nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) || 6888c2ecf20Sopenharmony_ci nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf)) 6898c2ecf20Sopenharmony_ci return -EMSGSIZE; 6908c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external)) 6918c2ecf20Sopenharmony_ci return -EMSGSIZE; 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PHYSICAL: 6948c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_CPU: 6958c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_DSA: 6968c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, 6978c2ecf20Sopenharmony_ci attrs->phys.port_number)) 6988c2ecf20Sopenharmony_ci return -EMSGSIZE; 6998c2ecf20Sopenharmony_ci if (!attrs->split) 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, 7028c2ecf20Sopenharmony_ci attrs->phys.port_number)) 7038c2ecf20Sopenharmony_ci return -EMSGSIZE; 7048c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER, 7058c2ecf20Sopenharmony_ci attrs->phys.split_subport_number)) 7068c2ecf20Sopenharmony_ci return -EMSGSIZE; 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci default: 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int 7158c2ecf20Sopenharmony_cidevlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port, 7168c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct devlink *devlink = port->devlink; 7198c2ecf20Sopenharmony_ci const struct devlink_ops *ops; 7208c2ecf20Sopenharmony_ci struct nlattr *function_attr; 7218c2ecf20Sopenharmony_ci bool empty_nest = true; 7228c2ecf20Sopenharmony_ci int err = 0; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION); 7258c2ecf20Sopenharmony_ci if (!function_attr) 7268c2ecf20Sopenharmony_ci return -EMSGSIZE; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci ops = devlink->ops; 7298c2ecf20Sopenharmony_ci if (ops->port_function_hw_addr_get) { 7308c2ecf20Sopenharmony_ci int hw_addr_len; 7318c2ecf20Sopenharmony_ci u8 hw_addr[MAX_ADDR_LEN]; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack); 7348c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 7358c2ecf20Sopenharmony_ci /* Port function attributes are optional for a port. If port doesn't 7368c2ecf20Sopenharmony_ci * support function attribute, returning -EOPNOTSUPP is not an error. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci err = 0; 7398c2ecf20Sopenharmony_ci goto out; 7408c2ecf20Sopenharmony_ci } else if (err) { 7418c2ecf20Sopenharmony_ci goto out; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr); 7448c2ecf20Sopenharmony_ci if (err) 7458c2ecf20Sopenharmony_ci goto out; 7468c2ecf20Sopenharmony_ci empty_nest = false; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciout: 7508c2ecf20Sopenharmony_ci if (err || empty_nest) 7518c2ecf20Sopenharmony_ci nla_nest_cancel(msg, function_attr); 7528c2ecf20Sopenharmony_ci else 7538c2ecf20Sopenharmony_ci nla_nest_end(msg, function_attr); 7548c2ecf20Sopenharmony_ci return err; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, 7588c2ecf20Sopenharmony_ci struct devlink_port *devlink_port, 7598c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 7608c2ecf20Sopenharmony_ci u32 seq, int flags, 7618c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci void *hdr; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 7668c2ecf20Sopenharmony_ci if (!hdr) 7678c2ecf20Sopenharmony_ci return -EMSGSIZE; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 7708c2ecf20Sopenharmony_ci goto nla_put_failure; 7718c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 7728c2ecf20Sopenharmony_ci goto nla_put_failure; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Hold rtnl lock while accessing port's netdev attributes. */ 7758c2ecf20Sopenharmony_ci rtnl_lock(); 7768c2ecf20Sopenharmony_ci spin_lock_bh(&devlink_port->type_lock); 7778c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type)) 7788c2ecf20Sopenharmony_ci goto nla_put_failure_type_locked; 7798c2ecf20Sopenharmony_ci if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET && 7808c2ecf20Sopenharmony_ci nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE, 7818c2ecf20Sopenharmony_ci devlink_port->desired_type)) 7828c2ecf20Sopenharmony_ci goto nla_put_failure_type_locked; 7838c2ecf20Sopenharmony_ci if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) { 7848c2ecf20Sopenharmony_ci struct net *net = devlink_net(devlink_port->devlink); 7858c2ecf20Sopenharmony_ci struct net_device *netdev = devlink_port->type_dev; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (netdev && net_eq(net, dev_net(netdev)) && 7888c2ecf20Sopenharmony_ci (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX, 7898c2ecf20Sopenharmony_ci netdev->ifindex) || 7908c2ecf20Sopenharmony_ci nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME, 7918c2ecf20Sopenharmony_ci netdev->name))) 7928c2ecf20Sopenharmony_ci goto nla_put_failure_type_locked; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci if (devlink_port->type == DEVLINK_PORT_TYPE_IB) { 7958c2ecf20Sopenharmony_ci struct ib_device *ibdev = devlink_port->type_dev; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (ibdev && 7988c2ecf20Sopenharmony_ci nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME, 7998c2ecf20Sopenharmony_ci ibdev->name)) 8008c2ecf20Sopenharmony_ci goto nla_put_failure_type_locked; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci spin_unlock_bh(&devlink_port->type_lock); 8038c2ecf20Sopenharmony_ci rtnl_unlock(); 8048c2ecf20Sopenharmony_ci if (devlink_nl_port_attrs_put(msg, devlink_port)) 8058c2ecf20Sopenharmony_ci goto nla_put_failure; 8068c2ecf20Sopenharmony_ci if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack)) 8078c2ecf20Sopenharmony_ci goto nla_put_failure; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cinla_put_failure_type_locked: 8138c2ecf20Sopenharmony_ci spin_unlock_bh(&devlink_port->type_lock); 8148c2ecf20Sopenharmony_ci rtnl_unlock(); 8158c2ecf20Sopenharmony_cinla_put_failure: 8168c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 8178c2ecf20Sopenharmony_ci return -EMSGSIZE; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic void devlink_port_notify(struct devlink_port *devlink_port, 8218c2ecf20Sopenharmony_ci enum devlink_command cmd) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 8248c2ecf20Sopenharmony_ci struct sk_buff *msg; 8258c2ecf20Sopenharmony_ci int err; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (!devlink_port->registered) 8288c2ecf20Sopenharmony_ci return; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 8338c2ecf20Sopenharmony_ci if (!msg) 8348c2ecf20Sopenharmony_ci return; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0, 8378c2ecf20Sopenharmony_ci NULL); 8388c2ecf20Sopenharmony_ci if (err) { 8398c2ecf20Sopenharmony_ci nlmsg_free(msg); 8408c2ecf20Sopenharmony_ci return; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 8448c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 8508c2ecf20Sopenharmony_ci struct sk_buff *msg; 8518c2ecf20Sopenharmony_ci int err; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 8548c2ecf20Sopenharmony_ci if (!msg) 8558c2ecf20Sopenharmony_ci return -ENOMEM; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, 8588c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 8598c2ecf20Sopenharmony_ci if (err) { 8608c2ecf20Sopenharmony_ci nlmsg_free(msg); 8618c2ecf20Sopenharmony_ci return err; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_get_dumpit(struct sk_buff *msg, 8688c2ecf20Sopenharmony_ci struct netlink_callback *cb) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct devlink *devlink; 8718c2ecf20Sopenharmony_ci int start = cb->args[0]; 8728c2ecf20Sopenharmony_ci int idx = 0; 8738c2ecf20Sopenharmony_ci int err; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 8768c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 8778c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 8788c2ecf20Sopenharmony_ci continue; 8798c2ecf20Sopenharmony_ci if (idx < start) { 8808c2ecf20Sopenharmony_ci idx++; 8818c2ecf20Sopenharmony_ci continue; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, 8848c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 8858c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, NLM_F_MULTI); 8868c2ecf20Sopenharmony_ci if (err) 8878c2ecf20Sopenharmony_ci goto out; 8888c2ecf20Sopenharmony_ci idx++; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ciout: 8918c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci cb->args[0] = idx; 8948c2ecf20Sopenharmony_ci return msg->len; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_get_doit(struct sk_buff *skb, 8988c2ecf20Sopenharmony_ci struct genl_info *info) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 9018c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 9028c2ecf20Sopenharmony_ci struct sk_buff *msg; 9038c2ecf20Sopenharmony_ci int err; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 9068c2ecf20Sopenharmony_ci if (!msg) 9078c2ecf20Sopenharmony_ci return -ENOMEM; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci err = devlink_nl_port_fill(msg, devlink, devlink_port, 9108c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_NEW, 9118c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0, 9128c2ecf20Sopenharmony_ci info->extack); 9138c2ecf20Sopenharmony_ci if (err) { 9148c2ecf20Sopenharmony_ci nlmsg_free(msg); 9158c2ecf20Sopenharmony_ci return err; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg, 9228c2ecf20Sopenharmony_ci struct netlink_callback *cb) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct devlink *devlink; 9258c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 9268c2ecf20Sopenharmony_ci int start = cb->args[0]; 9278c2ecf20Sopenharmony_ci int idx = 0; 9288c2ecf20Sopenharmony_ci int err; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 9318c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 9328c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 9338c2ecf20Sopenharmony_ci continue; 9348c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 9358c2ecf20Sopenharmony_ci list_for_each_entry(devlink_port, &devlink->port_list, list) { 9368c2ecf20Sopenharmony_ci if (idx < start) { 9378c2ecf20Sopenharmony_ci idx++; 9388c2ecf20Sopenharmony_ci continue; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci err = devlink_nl_port_fill(msg, devlink, devlink_port, 9418c2ecf20Sopenharmony_ci DEVLINK_CMD_NEW, 9428c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 9438c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 9448c2ecf20Sopenharmony_ci NLM_F_MULTI, 9458c2ecf20Sopenharmony_ci cb->extack); 9468c2ecf20Sopenharmony_ci if (err) { 9478c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 9488c2ecf20Sopenharmony_ci goto out; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci idx++; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ciout: 9558c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci cb->args[0] = idx; 9588c2ecf20Sopenharmony_ci return msg->len; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic int devlink_port_type_set(struct devlink *devlink, 9628c2ecf20Sopenharmony_ci struct devlink_port *devlink_port, 9638c2ecf20Sopenharmony_ci enum devlink_port_type port_type) 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci int err; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (devlink->ops->port_type_set) { 9698c2ecf20Sopenharmony_ci if (port_type == devlink_port->type) 9708c2ecf20Sopenharmony_ci return 0; 9718c2ecf20Sopenharmony_ci err = devlink->ops->port_type_set(devlink_port, port_type); 9728c2ecf20Sopenharmony_ci if (err) 9738c2ecf20Sopenharmony_ci return err; 9748c2ecf20Sopenharmony_ci devlink_port->desired_type = port_type; 9758c2ecf20Sopenharmony_ci devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic int 9828c2ecf20Sopenharmony_cidevlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port, 9838c2ecf20Sopenharmony_ci const struct nlattr *attr, struct netlink_ext_ack *extack) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci const struct devlink_ops *ops; 9868c2ecf20Sopenharmony_ci const u8 *hw_addr; 9878c2ecf20Sopenharmony_ci int hw_addr_len; 9888c2ecf20Sopenharmony_ci int err; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci hw_addr = nla_data(attr); 9918c2ecf20Sopenharmony_ci hw_addr_len = nla_len(attr); 9928c2ecf20Sopenharmony_ci if (hw_addr_len > MAX_ADDR_LEN) { 9938c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long"); 9948c2ecf20Sopenharmony_ci return -EINVAL; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci if (port->type == DEVLINK_PORT_TYPE_ETH) { 9978c2ecf20Sopenharmony_ci if (hw_addr_len != ETH_ALEN) { 9988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device"); 9998c2ecf20Sopenharmony_ci return -EINVAL; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci if (!is_unicast_ether_addr(hw_addr)) { 10028c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported"); 10038c2ecf20Sopenharmony_ci return -EINVAL; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci ops = devlink->ops; 10088c2ecf20Sopenharmony_ci if (!ops->port_function_hw_addr_set) { 10098c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes"); 10108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack); 10148c2ecf20Sopenharmony_ci if (err) 10158c2ecf20Sopenharmony_ci return err; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci devlink_port_notify(port, DEVLINK_CMD_PORT_NEW); 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int 10228c2ecf20Sopenharmony_cidevlink_port_function_set(struct devlink *devlink, struct devlink_port *port, 10238c2ecf20Sopenharmony_ci const struct nlattr *attr, struct netlink_ext_ack *extack) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1]; 10268c2ecf20Sopenharmony_ci int err; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr, 10298c2ecf20Sopenharmony_ci devlink_function_nl_policy, extack); 10308c2ecf20Sopenharmony_ci if (err < 0) { 10318c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes"); 10328c2ecf20Sopenharmony_ci return err; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]; 10368c2ecf20Sopenharmony_ci if (attr) 10378c2ecf20Sopenharmony_ci err = devlink_port_function_hw_addr_set(devlink, port, attr, extack); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci return err; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_set_doit(struct sk_buff *skb, 10438c2ecf20Sopenharmony_ci struct genl_info *info) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 10468c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 10478c2ecf20Sopenharmony_ci int err; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) { 10508c2ecf20Sopenharmony_ci enum devlink_port_type port_type; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]); 10538c2ecf20Sopenharmony_ci err = devlink_port_type_set(devlink, devlink_port, port_type); 10548c2ecf20Sopenharmony_ci if (err) 10558c2ecf20Sopenharmony_ci return err; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) { 10598c2ecf20Sopenharmony_ci struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION]; 10608c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci err = devlink_port_function_set(devlink, devlink_port, attr, extack); 10638c2ecf20Sopenharmony_ci if (err) 10648c2ecf20Sopenharmony_ci return err; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int devlink_port_split(struct devlink *devlink, u32 port_index, 10718c2ecf20Sopenharmony_ci u32 count, struct netlink_ext_ack *extack) 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci if (devlink->ops->port_split) 10758c2ecf20Sopenharmony_ci return devlink->ops->port_split(devlink, port_index, count, 10768c2ecf20Sopenharmony_ci extack); 10778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, 10818c2ecf20Sopenharmony_ci struct genl_info *info) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 10848c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 10858c2ecf20Sopenharmony_ci u32 port_index; 10868c2ecf20Sopenharmony_ci u32 count; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] || 10898c2ecf20Sopenharmony_ci !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]) 10908c2ecf20Sopenharmony_ci return -EINVAL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci devlink_port = devlink_port_get_from_info(devlink, info); 10938c2ecf20Sopenharmony_ci port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 10948c2ecf20Sopenharmony_ci count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (IS_ERR(devlink_port)) 10978c2ecf20Sopenharmony_ci return -EINVAL; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (!devlink_port->attrs.splittable) { 11008c2ecf20Sopenharmony_ci /* Split ports cannot be split. */ 11018c2ecf20Sopenharmony_ci if (devlink_port->attrs.split) 11028c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further"); 11038c2ecf20Sopenharmony_ci else 11048c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split"); 11058c2ecf20Sopenharmony_ci return -EINVAL; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) { 11098c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count"); 11108c2ecf20Sopenharmony_ci return -EINVAL; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return devlink_port_split(devlink, port_index, count, info->extack); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic int devlink_port_unsplit(struct devlink *devlink, u32 port_index, 11178c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci if (devlink->ops->port_unsplit) 11218c2ecf20Sopenharmony_ci return devlink->ops->port_unsplit(devlink, port_index, extack); 11228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, 11268c2ecf20Sopenharmony_ci struct genl_info *info) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 11298c2ecf20Sopenharmony_ci u32 port_index; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_PORT_INDEX]) 11328c2ecf20Sopenharmony_ci return -EINVAL; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 11358c2ecf20Sopenharmony_ci return devlink_port_unsplit(devlink, port_index, info->extack); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, 11398c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 11408c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 11418c2ecf20Sopenharmony_ci u32 seq, int flags) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci void *hdr; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 11468c2ecf20Sopenharmony_ci if (!hdr) 11478c2ecf20Sopenharmony_ci return -EMSGSIZE; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 11508c2ecf20Sopenharmony_ci goto nla_put_failure; 11518c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) 11528c2ecf20Sopenharmony_ci goto nla_put_failure; 11538c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size)) 11548c2ecf20Sopenharmony_ci goto nla_put_failure; 11558c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, 11568c2ecf20Sopenharmony_ci devlink_sb->ingress_pools_count)) 11578c2ecf20Sopenharmony_ci goto nla_put_failure; 11588c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, 11598c2ecf20Sopenharmony_ci devlink_sb->egress_pools_count)) 11608c2ecf20Sopenharmony_ci goto nla_put_failure; 11618c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT, 11628c2ecf20Sopenharmony_ci devlink_sb->ingress_tc_count)) 11638c2ecf20Sopenharmony_ci goto nla_put_failure; 11648c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT, 11658c2ecf20Sopenharmony_ci devlink_sb->egress_tc_count)) 11668c2ecf20Sopenharmony_ci goto nla_put_failure; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 11698c2ecf20Sopenharmony_ci return 0; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cinla_put_failure: 11728c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 11738c2ecf20Sopenharmony_ci return -EMSGSIZE; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb, 11778c2ecf20Sopenharmony_ci struct genl_info *info) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 11808c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 11818c2ecf20Sopenharmony_ci struct sk_buff *msg; 11828c2ecf20Sopenharmony_ci int err; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 11858c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 11868c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 11898c2ecf20Sopenharmony_ci if (!msg) 11908c2ecf20Sopenharmony_ci return -ENOMEM; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci err = devlink_nl_sb_fill(msg, devlink, devlink_sb, 11938c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_NEW, 11948c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 11958c2ecf20Sopenharmony_ci if (err) { 11968c2ecf20Sopenharmony_ci nlmsg_free(msg); 11978c2ecf20Sopenharmony_ci return err; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg, 12048c2ecf20Sopenharmony_ci struct netlink_callback *cb) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct devlink *devlink; 12078c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 12088c2ecf20Sopenharmony_ci int start = cb->args[0]; 12098c2ecf20Sopenharmony_ci int idx = 0; 12108c2ecf20Sopenharmony_ci int err; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 12138c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 12148c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 12158c2ecf20Sopenharmony_ci continue; 12168c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 12178c2ecf20Sopenharmony_ci list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 12188c2ecf20Sopenharmony_ci if (idx < start) { 12198c2ecf20Sopenharmony_ci idx++; 12208c2ecf20Sopenharmony_ci continue; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci err = devlink_nl_sb_fill(msg, devlink, devlink_sb, 12238c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_NEW, 12248c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 12258c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 12268c2ecf20Sopenharmony_ci NLM_F_MULTI); 12278c2ecf20Sopenharmony_ci if (err) { 12288c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 12298c2ecf20Sopenharmony_ci goto out; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci idx++; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ciout: 12368c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci cb->args[0] = idx; 12398c2ecf20Sopenharmony_ci return msg->len; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink, 12438c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 12448c2ecf20Sopenharmony_ci u16 pool_index, enum devlink_command cmd, 12458c2ecf20Sopenharmony_ci u32 portid, u32 seq, int flags) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci struct devlink_sb_pool_info pool_info; 12488c2ecf20Sopenharmony_ci void *hdr; 12498c2ecf20Sopenharmony_ci int err; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci err = devlink->ops->sb_pool_get(devlink, devlink_sb->index, 12528c2ecf20Sopenharmony_ci pool_index, &pool_info); 12538c2ecf20Sopenharmony_ci if (err) 12548c2ecf20Sopenharmony_ci return err; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 12578c2ecf20Sopenharmony_ci if (!hdr) 12588c2ecf20Sopenharmony_ci return -EMSGSIZE; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 12618c2ecf20Sopenharmony_ci goto nla_put_failure; 12628c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) 12638c2ecf20Sopenharmony_ci goto nla_put_failure; 12648c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) 12658c2ecf20Sopenharmony_ci goto nla_put_failure; 12668c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type)) 12678c2ecf20Sopenharmony_ci goto nla_put_failure; 12688c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size)) 12698c2ecf20Sopenharmony_ci goto nla_put_failure; 12708c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, 12718c2ecf20Sopenharmony_ci pool_info.threshold_type)) 12728c2ecf20Sopenharmony_ci goto nla_put_failure; 12738c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE, 12748c2ecf20Sopenharmony_ci pool_info.cell_size)) 12758c2ecf20Sopenharmony_ci goto nla_put_failure; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cinla_put_failure: 12818c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 12828c2ecf20Sopenharmony_ci return -EMSGSIZE; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb, 12868c2ecf20Sopenharmony_ci struct genl_info *info) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 12898c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 12908c2ecf20Sopenharmony_ci struct sk_buff *msg; 12918c2ecf20Sopenharmony_ci u16 pool_index; 12928c2ecf20Sopenharmony_ci int err; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 12958c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 12968c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci err = devlink_sb_pool_index_get_from_info(devlink_sb, info, 12998c2ecf20Sopenharmony_ci &pool_index); 13008c2ecf20Sopenharmony_ci if (err) 13018c2ecf20Sopenharmony_ci return err; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (!devlink->ops->sb_pool_get) 13048c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 13078c2ecf20Sopenharmony_ci if (!msg) 13088c2ecf20Sopenharmony_ci return -ENOMEM; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index, 13118c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_POOL_NEW, 13128c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 13138c2ecf20Sopenharmony_ci if (err) { 13148c2ecf20Sopenharmony_ci nlmsg_free(msg); 13158c2ecf20Sopenharmony_ci return err; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx, 13228c2ecf20Sopenharmony_ci struct devlink *devlink, 13238c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 13248c2ecf20Sopenharmony_ci u32 portid, u32 seq) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci u16 pool_count = devlink_sb_pool_count(devlink_sb); 13278c2ecf20Sopenharmony_ci u16 pool_index; 13288c2ecf20Sopenharmony_ci int err; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci for (pool_index = 0; pool_index < pool_count; pool_index++) { 13318c2ecf20Sopenharmony_ci if (*p_idx < start) { 13328c2ecf20Sopenharmony_ci (*p_idx)++; 13338c2ecf20Sopenharmony_ci continue; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci err = devlink_nl_sb_pool_fill(msg, devlink, 13368c2ecf20Sopenharmony_ci devlink_sb, 13378c2ecf20Sopenharmony_ci pool_index, 13388c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_POOL_NEW, 13398c2ecf20Sopenharmony_ci portid, seq, NLM_F_MULTI); 13408c2ecf20Sopenharmony_ci if (err) 13418c2ecf20Sopenharmony_ci return err; 13428c2ecf20Sopenharmony_ci (*p_idx)++; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci return 0; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg, 13488c2ecf20Sopenharmony_ci struct netlink_callback *cb) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct devlink *devlink; 13518c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 13528c2ecf20Sopenharmony_ci int start = cb->args[0]; 13538c2ecf20Sopenharmony_ci int idx = 0; 13548c2ecf20Sopenharmony_ci int err = 0; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 13578c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 13588c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 13598c2ecf20Sopenharmony_ci !devlink->ops->sb_pool_get) 13608c2ecf20Sopenharmony_ci continue; 13618c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 13628c2ecf20Sopenharmony_ci list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 13638c2ecf20Sopenharmony_ci err = __sb_pool_get_dumpit(msg, start, &idx, devlink, 13648c2ecf20Sopenharmony_ci devlink_sb, 13658c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 13668c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq); 13678c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 13688c2ecf20Sopenharmony_ci err = 0; 13698c2ecf20Sopenharmony_ci } else if (err) { 13708c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 13718c2ecf20Sopenharmony_ci goto out; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ciout: 13778c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 13808c2ecf20Sopenharmony_ci return err; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci cb->args[0] = idx; 13838c2ecf20Sopenharmony_ci return msg->len; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index, 13878c2ecf20Sopenharmony_ci u16 pool_index, u32 size, 13888c2ecf20Sopenharmony_ci enum devlink_sb_threshold_type threshold_type, 13898c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (ops->sb_pool_set) 13958c2ecf20Sopenharmony_ci return ops->sb_pool_set(devlink, sb_index, pool_index, 13968c2ecf20Sopenharmony_ci size, threshold_type, extack); 13978c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb, 14018c2ecf20Sopenharmony_ci struct genl_info *info) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 14048c2ecf20Sopenharmony_ci enum devlink_sb_threshold_type threshold_type; 14058c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 14068c2ecf20Sopenharmony_ci u16 pool_index; 14078c2ecf20Sopenharmony_ci u32 size; 14088c2ecf20Sopenharmony_ci int err; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 14118c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 14128c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci err = devlink_sb_pool_index_get_from_info(devlink_sb, info, 14158c2ecf20Sopenharmony_ci &pool_index); 14168c2ecf20Sopenharmony_ci if (err) 14178c2ecf20Sopenharmony_ci return err; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci err = devlink_sb_th_type_get_from_info(info, &threshold_type); 14208c2ecf20Sopenharmony_ci if (err) 14218c2ecf20Sopenharmony_ci return err; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]) 14248c2ecf20Sopenharmony_ci return -EINVAL; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]); 14278c2ecf20Sopenharmony_ci return devlink_sb_pool_set(devlink, devlink_sb->index, 14288c2ecf20Sopenharmony_ci pool_index, size, threshold_type, 14298c2ecf20Sopenharmony_ci info->extack); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistatic int devlink_nl_sb_port_pool_fill(struct sk_buff *msg, 14338c2ecf20Sopenharmony_ci struct devlink *devlink, 14348c2ecf20Sopenharmony_ci struct devlink_port *devlink_port, 14358c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 14368c2ecf20Sopenharmony_ci u16 pool_index, 14378c2ecf20Sopenharmony_ci enum devlink_command cmd, 14388c2ecf20Sopenharmony_ci u32 portid, u32 seq, int flags) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 14418c2ecf20Sopenharmony_ci u32 threshold; 14428c2ecf20Sopenharmony_ci void *hdr; 14438c2ecf20Sopenharmony_ci int err; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci err = ops->sb_port_pool_get(devlink_port, devlink_sb->index, 14468c2ecf20Sopenharmony_ci pool_index, &threshold); 14478c2ecf20Sopenharmony_ci if (err) 14488c2ecf20Sopenharmony_ci return err; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 14518c2ecf20Sopenharmony_ci if (!hdr) 14528c2ecf20Sopenharmony_ci return -EMSGSIZE; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 14558c2ecf20Sopenharmony_ci goto nla_put_failure; 14568c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 14578c2ecf20Sopenharmony_ci goto nla_put_failure; 14588c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) 14598c2ecf20Sopenharmony_ci goto nla_put_failure; 14608c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) 14618c2ecf20Sopenharmony_ci goto nla_put_failure; 14628c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) 14638c2ecf20Sopenharmony_ci goto nla_put_failure; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (ops->sb_occ_port_pool_get) { 14668c2ecf20Sopenharmony_ci u32 cur; 14678c2ecf20Sopenharmony_ci u32 max; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index, 14708c2ecf20Sopenharmony_ci pool_index, &cur, &max); 14718c2ecf20Sopenharmony_ci if (err && err != -EOPNOTSUPP) 14728c2ecf20Sopenharmony_ci goto sb_occ_get_failure; 14738c2ecf20Sopenharmony_ci if (!err) { 14748c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur)) 14758c2ecf20Sopenharmony_ci goto nla_put_failure; 14768c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max)) 14778c2ecf20Sopenharmony_ci goto nla_put_failure; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 14828c2ecf20Sopenharmony_ci return 0; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cinla_put_failure: 14858c2ecf20Sopenharmony_ci err = -EMSGSIZE; 14868c2ecf20Sopenharmony_cisb_occ_get_failure: 14878c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 14888c2ecf20Sopenharmony_ci return err; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb, 14928c2ecf20Sopenharmony_ci struct genl_info *info) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 14958c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 14968c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 14978c2ecf20Sopenharmony_ci struct sk_buff *msg; 14988c2ecf20Sopenharmony_ci u16 pool_index; 14998c2ecf20Sopenharmony_ci int err; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 15028c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 15038c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci err = devlink_sb_pool_index_get_from_info(devlink_sb, info, 15068c2ecf20Sopenharmony_ci &pool_index); 15078c2ecf20Sopenharmony_ci if (err) 15088c2ecf20Sopenharmony_ci return err; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (!devlink->ops->sb_port_pool_get) 15118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 15148c2ecf20Sopenharmony_ci if (!msg) 15158c2ecf20Sopenharmony_ci return -ENOMEM; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port, 15188c2ecf20Sopenharmony_ci devlink_sb, pool_index, 15198c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_PORT_POOL_NEW, 15208c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 15218c2ecf20Sopenharmony_ci if (err) { 15228c2ecf20Sopenharmony_ci nlmsg_free(msg); 15238c2ecf20Sopenharmony_ci return err; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx, 15308c2ecf20Sopenharmony_ci struct devlink *devlink, 15318c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 15328c2ecf20Sopenharmony_ci u32 portid, u32 seq) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 15358c2ecf20Sopenharmony_ci u16 pool_count = devlink_sb_pool_count(devlink_sb); 15368c2ecf20Sopenharmony_ci u16 pool_index; 15378c2ecf20Sopenharmony_ci int err; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci list_for_each_entry(devlink_port, &devlink->port_list, list) { 15408c2ecf20Sopenharmony_ci for (pool_index = 0; pool_index < pool_count; pool_index++) { 15418c2ecf20Sopenharmony_ci if (*p_idx < start) { 15428c2ecf20Sopenharmony_ci (*p_idx)++; 15438c2ecf20Sopenharmony_ci continue; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci err = devlink_nl_sb_port_pool_fill(msg, devlink, 15468c2ecf20Sopenharmony_ci devlink_port, 15478c2ecf20Sopenharmony_ci devlink_sb, 15488c2ecf20Sopenharmony_ci pool_index, 15498c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_PORT_POOL_NEW, 15508c2ecf20Sopenharmony_ci portid, seq, 15518c2ecf20Sopenharmony_ci NLM_F_MULTI); 15528c2ecf20Sopenharmony_ci if (err) 15538c2ecf20Sopenharmony_ci return err; 15548c2ecf20Sopenharmony_ci (*p_idx)++; 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci return 0; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg, 15618c2ecf20Sopenharmony_ci struct netlink_callback *cb) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci struct devlink *devlink; 15648c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 15658c2ecf20Sopenharmony_ci int start = cb->args[0]; 15668c2ecf20Sopenharmony_ci int idx = 0; 15678c2ecf20Sopenharmony_ci int err = 0; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 15708c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 15718c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 15728c2ecf20Sopenharmony_ci !devlink->ops->sb_port_pool_get) 15738c2ecf20Sopenharmony_ci continue; 15748c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 15758c2ecf20Sopenharmony_ci list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 15768c2ecf20Sopenharmony_ci err = __sb_port_pool_get_dumpit(msg, start, &idx, 15778c2ecf20Sopenharmony_ci devlink, devlink_sb, 15788c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 15798c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq); 15808c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 15818c2ecf20Sopenharmony_ci err = 0; 15828c2ecf20Sopenharmony_ci } else if (err) { 15838c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 15848c2ecf20Sopenharmony_ci goto out; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ciout: 15908c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 15938c2ecf20Sopenharmony_ci return err; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci cb->args[0] = idx; 15968c2ecf20Sopenharmony_ci return msg->len; 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic int devlink_sb_port_pool_set(struct devlink_port *devlink_port, 16008c2ecf20Sopenharmony_ci unsigned int sb_index, u16 pool_index, 16018c2ecf20Sopenharmony_ci u32 threshold, 16028c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink_port->devlink->ops; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (ops->sb_port_pool_set) 16088c2ecf20Sopenharmony_ci return ops->sb_port_pool_set(devlink_port, sb_index, 16098c2ecf20Sopenharmony_ci pool_index, threshold, extack); 16108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb, 16148c2ecf20Sopenharmony_ci struct genl_info *info) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 16178c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 16188c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 16198c2ecf20Sopenharmony_ci u16 pool_index; 16208c2ecf20Sopenharmony_ci u32 threshold; 16218c2ecf20Sopenharmony_ci int err; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 16248c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 16258c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci err = devlink_sb_pool_index_get_from_info(devlink_sb, info, 16288c2ecf20Sopenharmony_ci &pool_index); 16298c2ecf20Sopenharmony_ci if (err) 16308c2ecf20Sopenharmony_ci return err; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD]) 16338c2ecf20Sopenharmony_ci return -EINVAL; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]); 16368c2ecf20Sopenharmony_ci return devlink_sb_port_pool_set(devlink_port, devlink_sb->index, 16378c2ecf20Sopenharmony_ci pool_index, threshold, info->extack); 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_cistatic int 16418c2ecf20Sopenharmony_cidevlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink, 16428c2ecf20Sopenharmony_ci struct devlink_port *devlink_port, 16438c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, u16 tc_index, 16448c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type, 16458c2ecf20Sopenharmony_ci enum devlink_command cmd, 16468c2ecf20Sopenharmony_ci u32 portid, u32 seq, int flags) 16478c2ecf20Sopenharmony_ci{ 16488c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 16498c2ecf20Sopenharmony_ci u16 pool_index; 16508c2ecf20Sopenharmony_ci u32 threshold; 16518c2ecf20Sopenharmony_ci void *hdr; 16528c2ecf20Sopenharmony_ci int err; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index, 16558c2ecf20Sopenharmony_ci tc_index, pool_type, 16568c2ecf20Sopenharmony_ci &pool_index, &threshold); 16578c2ecf20Sopenharmony_ci if (err) 16588c2ecf20Sopenharmony_ci return err; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 16618c2ecf20Sopenharmony_ci if (!hdr) 16628c2ecf20Sopenharmony_ci return -EMSGSIZE; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 16658c2ecf20Sopenharmony_ci goto nla_put_failure; 16668c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 16678c2ecf20Sopenharmony_ci goto nla_put_failure; 16688c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) 16698c2ecf20Sopenharmony_ci goto nla_put_failure; 16708c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index)) 16718c2ecf20Sopenharmony_ci goto nla_put_failure; 16728c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type)) 16738c2ecf20Sopenharmony_ci goto nla_put_failure; 16748c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) 16758c2ecf20Sopenharmony_ci goto nla_put_failure; 16768c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) 16778c2ecf20Sopenharmony_ci goto nla_put_failure; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (ops->sb_occ_tc_port_bind_get) { 16808c2ecf20Sopenharmony_ci u32 cur; 16818c2ecf20Sopenharmony_ci u32 max; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci err = ops->sb_occ_tc_port_bind_get(devlink_port, 16848c2ecf20Sopenharmony_ci devlink_sb->index, 16858c2ecf20Sopenharmony_ci tc_index, pool_type, 16868c2ecf20Sopenharmony_ci &cur, &max); 16878c2ecf20Sopenharmony_ci if (err && err != -EOPNOTSUPP) 16888c2ecf20Sopenharmony_ci return err; 16898c2ecf20Sopenharmony_ci if (!err) { 16908c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur)) 16918c2ecf20Sopenharmony_ci goto nla_put_failure; 16928c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max)) 16938c2ecf20Sopenharmony_ci goto nla_put_failure; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 16988c2ecf20Sopenharmony_ci return 0; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cinla_put_failure: 17018c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 17028c2ecf20Sopenharmony_ci return -EMSGSIZE; 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb, 17068c2ecf20Sopenharmony_ci struct genl_info *info) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 17098c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 17108c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 17118c2ecf20Sopenharmony_ci struct sk_buff *msg; 17128c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type; 17138c2ecf20Sopenharmony_ci u16 tc_index; 17148c2ecf20Sopenharmony_ci int err; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 17178c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 17188c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci err = devlink_sb_pool_type_get_from_info(info, &pool_type); 17218c2ecf20Sopenharmony_ci if (err) 17228c2ecf20Sopenharmony_ci return err; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci err = devlink_sb_tc_index_get_from_info(devlink_sb, info, 17258c2ecf20Sopenharmony_ci pool_type, &tc_index); 17268c2ecf20Sopenharmony_ci if (err) 17278c2ecf20Sopenharmony_ci return err; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (!devlink->ops->sb_tc_pool_bind_get) 17308c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 17338c2ecf20Sopenharmony_ci if (!msg) 17348c2ecf20Sopenharmony_ci return -ENOMEM; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port, 17378c2ecf20Sopenharmony_ci devlink_sb, tc_index, pool_type, 17388c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_TC_POOL_BIND_NEW, 17398c2ecf20Sopenharmony_ci info->snd_portid, 17408c2ecf20Sopenharmony_ci info->snd_seq, 0); 17418c2ecf20Sopenharmony_ci if (err) { 17428c2ecf20Sopenharmony_ci nlmsg_free(msg); 17438c2ecf20Sopenharmony_ci return err; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg, 17508c2ecf20Sopenharmony_ci int start, int *p_idx, 17518c2ecf20Sopenharmony_ci struct devlink *devlink, 17528c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb, 17538c2ecf20Sopenharmony_ci u32 portid, u32 seq) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 17568c2ecf20Sopenharmony_ci u16 tc_index; 17578c2ecf20Sopenharmony_ci int err; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci list_for_each_entry(devlink_port, &devlink->port_list, list) { 17608c2ecf20Sopenharmony_ci for (tc_index = 0; 17618c2ecf20Sopenharmony_ci tc_index < devlink_sb->ingress_tc_count; tc_index++) { 17628c2ecf20Sopenharmony_ci if (*p_idx < start) { 17638c2ecf20Sopenharmony_ci (*p_idx)++; 17648c2ecf20Sopenharmony_ci continue; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, 17678c2ecf20Sopenharmony_ci devlink_port, 17688c2ecf20Sopenharmony_ci devlink_sb, 17698c2ecf20Sopenharmony_ci tc_index, 17708c2ecf20Sopenharmony_ci DEVLINK_SB_POOL_TYPE_INGRESS, 17718c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_TC_POOL_BIND_NEW, 17728c2ecf20Sopenharmony_ci portid, seq, 17738c2ecf20Sopenharmony_ci NLM_F_MULTI); 17748c2ecf20Sopenharmony_ci if (err) 17758c2ecf20Sopenharmony_ci return err; 17768c2ecf20Sopenharmony_ci (*p_idx)++; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci for (tc_index = 0; 17798c2ecf20Sopenharmony_ci tc_index < devlink_sb->egress_tc_count; tc_index++) { 17808c2ecf20Sopenharmony_ci if (*p_idx < start) { 17818c2ecf20Sopenharmony_ci (*p_idx)++; 17828c2ecf20Sopenharmony_ci continue; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, 17858c2ecf20Sopenharmony_ci devlink_port, 17868c2ecf20Sopenharmony_ci devlink_sb, 17878c2ecf20Sopenharmony_ci tc_index, 17888c2ecf20Sopenharmony_ci DEVLINK_SB_POOL_TYPE_EGRESS, 17898c2ecf20Sopenharmony_ci DEVLINK_CMD_SB_TC_POOL_BIND_NEW, 17908c2ecf20Sopenharmony_ci portid, seq, 17918c2ecf20Sopenharmony_ci NLM_F_MULTI); 17928c2ecf20Sopenharmony_ci if (err) 17938c2ecf20Sopenharmony_ci return err; 17948c2ecf20Sopenharmony_ci (*p_idx)++; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci return 0; 17988c2ecf20Sopenharmony_ci} 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_cistatic int 18018c2ecf20Sopenharmony_cidevlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg, 18028c2ecf20Sopenharmony_ci struct netlink_callback *cb) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci struct devlink *devlink; 18058c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 18068c2ecf20Sopenharmony_ci int start = cb->args[0]; 18078c2ecf20Sopenharmony_ci int idx = 0; 18088c2ecf20Sopenharmony_ci int err = 0; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 18118c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 18128c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 18138c2ecf20Sopenharmony_ci !devlink->ops->sb_tc_pool_bind_get) 18148c2ecf20Sopenharmony_ci continue; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 18178c2ecf20Sopenharmony_ci list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 18188c2ecf20Sopenharmony_ci err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx, 18198c2ecf20Sopenharmony_ci devlink, 18208c2ecf20Sopenharmony_ci devlink_sb, 18218c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 18228c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq); 18238c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 18248c2ecf20Sopenharmony_ci err = 0; 18258c2ecf20Sopenharmony_ci } else if (err) { 18268c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 18278c2ecf20Sopenharmony_ci goto out; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ciout: 18338c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 18368c2ecf20Sopenharmony_ci return err; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci cb->args[0] = idx; 18398c2ecf20Sopenharmony_ci return msg->len; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cistatic int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, 18438c2ecf20Sopenharmony_ci unsigned int sb_index, u16 tc_index, 18448c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type, 18458c2ecf20Sopenharmony_ci u16 pool_index, u32 threshold, 18468c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink_port->devlink->ops; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci if (ops->sb_tc_pool_bind_set) 18528c2ecf20Sopenharmony_ci return ops->sb_tc_pool_bind_set(devlink_port, sb_index, 18538c2ecf20Sopenharmony_ci tc_index, pool_type, 18548c2ecf20Sopenharmony_ci pool_index, threshold, extack); 18558c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb, 18598c2ecf20Sopenharmony_ci struct genl_info *info) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 18628c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 18638c2ecf20Sopenharmony_ci enum devlink_sb_pool_type pool_type; 18648c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 18658c2ecf20Sopenharmony_ci u16 tc_index; 18668c2ecf20Sopenharmony_ci u16 pool_index; 18678c2ecf20Sopenharmony_ci u32 threshold; 18688c2ecf20Sopenharmony_ci int err; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 18718c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 18728c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci err = devlink_sb_pool_type_get_from_info(info, &pool_type); 18758c2ecf20Sopenharmony_ci if (err) 18768c2ecf20Sopenharmony_ci return err; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci err = devlink_sb_tc_index_get_from_info(devlink_sb, info, 18798c2ecf20Sopenharmony_ci pool_type, &tc_index); 18808c2ecf20Sopenharmony_ci if (err) 18818c2ecf20Sopenharmony_ci return err; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci err = devlink_sb_pool_index_get_from_info(devlink_sb, info, 18848c2ecf20Sopenharmony_ci &pool_index); 18858c2ecf20Sopenharmony_ci if (err) 18868c2ecf20Sopenharmony_ci return err; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD]) 18898c2ecf20Sopenharmony_ci return -EINVAL; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]); 18928c2ecf20Sopenharmony_ci return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index, 18938c2ecf20Sopenharmony_ci tc_index, pool_type, 18948c2ecf20Sopenharmony_ci pool_index, threshold, info->extack); 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb, 18988c2ecf20Sopenharmony_ci struct genl_info *info) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 19018c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 19028c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 19058c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 19068c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (ops->sb_occ_snapshot) 19098c2ecf20Sopenharmony_ci return ops->sb_occ_snapshot(devlink, devlink_sb->index); 19108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb, 19148c2ecf20Sopenharmony_ci struct genl_info *info) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 19178c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 19188c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_from_info(devlink, info); 19218c2ecf20Sopenharmony_ci if (IS_ERR(devlink_sb)) 19228c2ecf20Sopenharmony_ci return PTR_ERR(devlink_sb); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (ops->sb_occ_max_clear) 19258c2ecf20Sopenharmony_ci return ops->sb_occ_max_clear(devlink, devlink_sb->index); 19268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19278c2ecf20Sopenharmony_ci} 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_cistatic int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink, 19308c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 19318c2ecf20Sopenharmony_ci u32 seq, int flags) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 19348c2ecf20Sopenharmony_ci enum devlink_eswitch_encap_mode encap_mode; 19358c2ecf20Sopenharmony_ci u8 inline_mode; 19368c2ecf20Sopenharmony_ci void *hdr; 19378c2ecf20Sopenharmony_ci int err = 0; 19388c2ecf20Sopenharmony_ci u16 mode; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 19418c2ecf20Sopenharmony_ci if (!hdr) 19428c2ecf20Sopenharmony_ci return -EMSGSIZE; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci err = devlink_nl_put_handle(msg, devlink); 19458c2ecf20Sopenharmony_ci if (err) 19468c2ecf20Sopenharmony_ci goto nla_put_failure; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci if (ops->eswitch_mode_get) { 19498c2ecf20Sopenharmony_ci err = ops->eswitch_mode_get(devlink, &mode); 19508c2ecf20Sopenharmony_ci if (err) 19518c2ecf20Sopenharmony_ci goto nla_put_failure; 19528c2ecf20Sopenharmony_ci err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode); 19538c2ecf20Sopenharmony_ci if (err) 19548c2ecf20Sopenharmony_ci goto nla_put_failure; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (ops->eswitch_inline_mode_get) { 19588c2ecf20Sopenharmony_ci err = ops->eswitch_inline_mode_get(devlink, &inline_mode); 19598c2ecf20Sopenharmony_ci if (err) 19608c2ecf20Sopenharmony_ci goto nla_put_failure; 19618c2ecf20Sopenharmony_ci err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE, 19628c2ecf20Sopenharmony_ci inline_mode); 19638c2ecf20Sopenharmony_ci if (err) 19648c2ecf20Sopenharmony_ci goto nla_put_failure; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (ops->eswitch_encap_mode_get) { 19688c2ecf20Sopenharmony_ci err = ops->eswitch_encap_mode_get(devlink, &encap_mode); 19698c2ecf20Sopenharmony_ci if (err) 19708c2ecf20Sopenharmony_ci goto nla_put_failure; 19718c2ecf20Sopenharmony_ci err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode); 19728c2ecf20Sopenharmony_ci if (err) 19738c2ecf20Sopenharmony_ci goto nla_put_failure; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 19778c2ecf20Sopenharmony_ci return 0; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_cinla_put_failure: 19808c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 19818c2ecf20Sopenharmony_ci return err; 19828c2ecf20Sopenharmony_ci} 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, 19858c2ecf20Sopenharmony_ci struct genl_info *info) 19868c2ecf20Sopenharmony_ci{ 19878c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 19888c2ecf20Sopenharmony_ci struct sk_buff *msg; 19898c2ecf20Sopenharmony_ci int err; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 19928c2ecf20Sopenharmony_ci if (!msg) 19938c2ecf20Sopenharmony_ci return -ENOMEM; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET, 19968c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci if (err) { 19998c2ecf20Sopenharmony_ci nlmsg_free(msg); 20008c2ecf20Sopenharmony_ci return err; 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, 20078c2ecf20Sopenharmony_ci struct genl_info *info) 20088c2ecf20Sopenharmony_ci{ 20098c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 20108c2ecf20Sopenharmony_ci const struct devlink_ops *ops = devlink->ops; 20118c2ecf20Sopenharmony_ci enum devlink_eswitch_encap_mode encap_mode; 20128c2ecf20Sopenharmony_ci u8 inline_mode; 20138c2ecf20Sopenharmony_ci int err = 0; 20148c2ecf20Sopenharmony_ci u16 mode; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) { 20178c2ecf20Sopenharmony_ci if (!ops->eswitch_mode_set) 20188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20198c2ecf20Sopenharmony_ci mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]); 20208c2ecf20Sopenharmony_ci err = ops->eswitch_mode_set(devlink, mode, info->extack); 20218c2ecf20Sopenharmony_ci if (err) 20228c2ecf20Sopenharmony_ci return err; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) { 20268c2ecf20Sopenharmony_ci if (!ops->eswitch_inline_mode_set) 20278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20288c2ecf20Sopenharmony_ci inline_mode = nla_get_u8( 20298c2ecf20Sopenharmony_ci info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]); 20308c2ecf20Sopenharmony_ci err = ops->eswitch_inline_mode_set(devlink, inline_mode, 20318c2ecf20Sopenharmony_ci info->extack); 20328c2ecf20Sopenharmony_ci if (err) 20338c2ecf20Sopenharmony_ci return err; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) { 20378c2ecf20Sopenharmony_ci if (!ops->eswitch_encap_mode_set) 20388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20398c2ecf20Sopenharmony_ci encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]); 20408c2ecf20Sopenharmony_ci err = ops->eswitch_encap_mode_set(devlink, encap_mode, 20418c2ecf20Sopenharmony_ci info->extack); 20428c2ecf20Sopenharmony_ci if (err) 20438c2ecf20Sopenharmony_ci return err; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci return 0; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ciint devlink_dpipe_match_put(struct sk_buff *skb, 20508c2ecf20Sopenharmony_ci struct devlink_dpipe_match *match) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct devlink_dpipe_header *header = match->header; 20538c2ecf20Sopenharmony_ci struct devlink_dpipe_field *field = &header->fields[match->field_id]; 20548c2ecf20Sopenharmony_ci struct nlattr *match_attr; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH); 20578c2ecf20Sopenharmony_ci if (!match_attr) 20588c2ecf20Sopenharmony_ci return -EMSGSIZE; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) || 20618c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) || 20628c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 20638c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 20648c2ecf20Sopenharmony_ci nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 20658c2ecf20Sopenharmony_ci goto nla_put_failure; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci nla_nest_end(skb, match_attr); 20688c2ecf20Sopenharmony_ci return 0; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_cinla_put_failure: 20718c2ecf20Sopenharmony_ci nla_nest_cancel(skb, match_attr); 20728c2ecf20Sopenharmony_ci return -EMSGSIZE; 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_match_put); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic int devlink_dpipe_matches_put(struct devlink_dpipe_table *table, 20778c2ecf20Sopenharmony_ci struct sk_buff *skb) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct nlattr *matches_attr; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci matches_attr = nla_nest_start_noflag(skb, 20828c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_TABLE_MATCHES); 20838c2ecf20Sopenharmony_ci if (!matches_attr) 20848c2ecf20Sopenharmony_ci return -EMSGSIZE; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (table->table_ops->matches_dump(table->priv, skb)) 20878c2ecf20Sopenharmony_ci goto nla_put_failure; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci nla_nest_end(skb, matches_attr); 20908c2ecf20Sopenharmony_ci return 0; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cinla_put_failure: 20938c2ecf20Sopenharmony_ci nla_nest_cancel(skb, matches_attr); 20948c2ecf20Sopenharmony_ci return -EMSGSIZE; 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ciint devlink_dpipe_action_put(struct sk_buff *skb, 20988c2ecf20Sopenharmony_ci struct devlink_dpipe_action *action) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci struct devlink_dpipe_header *header = action->header; 21018c2ecf20Sopenharmony_ci struct devlink_dpipe_field *field = &header->fields[action->field_id]; 21028c2ecf20Sopenharmony_ci struct nlattr *action_attr; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION); 21058c2ecf20Sopenharmony_ci if (!action_attr) 21068c2ecf20Sopenharmony_ci return -EMSGSIZE; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) || 21098c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) || 21108c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 21118c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 21128c2ecf20Sopenharmony_ci nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 21138c2ecf20Sopenharmony_ci goto nla_put_failure; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci nla_nest_end(skb, action_attr); 21168c2ecf20Sopenharmony_ci return 0; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_cinla_put_failure: 21198c2ecf20Sopenharmony_ci nla_nest_cancel(skb, action_attr); 21208c2ecf20Sopenharmony_ci return -EMSGSIZE; 21218c2ecf20Sopenharmony_ci} 21228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_action_put); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int devlink_dpipe_actions_put(struct devlink_dpipe_table *table, 21258c2ecf20Sopenharmony_ci struct sk_buff *skb) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci struct nlattr *actions_attr; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci actions_attr = nla_nest_start_noflag(skb, 21308c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_TABLE_ACTIONS); 21318c2ecf20Sopenharmony_ci if (!actions_attr) 21328c2ecf20Sopenharmony_ci return -EMSGSIZE; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (table->table_ops->actions_dump(table->priv, skb)) 21358c2ecf20Sopenharmony_ci goto nla_put_failure; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci nla_nest_end(skb, actions_attr); 21388c2ecf20Sopenharmony_ci return 0; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cinla_put_failure: 21418c2ecf20Sopenharmony_ci nla_nest_cancel(skb, actions_attr); 21428c2ecf20Sopenharmony_ci return -EMSGSIZE; 21438c2ecf20Sopenharmony_ci} 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_cistatic int devlink_dpipe_table_put(struct sk_buff *skb, 21468c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci struct nlattr *table_attr; 21498c2ecf20Sopenharmony_ci u64 table_size; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci table_size = table->table_ops->size_get(table->priv); 21528c2ecf20Sopenharmony_ci table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE); 21538c2ecf20Sopenharmony_ci if (!table_attr) 21548c2ecf20Sopenharmony_ci return -EMSGSIZE; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) || 21578c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size, 21588c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 21598c2ecf20Sopenharmony_ci goto nla_put_failure; 21608c2ecf20Sopenharmony_ci if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, 21618c2ecf20Sopenharmony_ci table->counters_enabled)) 21628c2ecf20Sopenharmony_ci goto nla_put_failure; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (table->resource_valid) { 21658c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, 21668c2ecf20Sopenharmony_ci table->resource_id, DEVLINK_ATTR_PAD) || 21678c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, 21688c2ecf20Sopenharmony_ci table->resource_units, DEVLINK_ATTR_PAD)) 21698c2ecf20Sopenharmony_ci goto nla_put_failure; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci if (devlink_dpipe_matches_put(table, skb)) 21728c2ecf20Sopenharmony_ci goto nla_put_failure; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci if (devlink_dpipe_actions_put(table, skb)) 21758c2ecf20Sopenharmony_ci goto nla_put_failure; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci nla_nest_end(skb, table_attr); 21788c2ecf20Sopenharmony_ci return 0; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_cinla_put_failure: 21818c2ecf20Sopenharmony_ci nla_nest_cancel(skb, table_attr); 21828c2ecf20Sopenharmony_ci return -EMSGSIZE; 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cistatic int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb, 21868c2ecf20Sopenharmony_ci struct genl_info *info) 21878c2ecf20Sopenharmony_ci{ 21888c2ecf20Sopenharmony_ci int err; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci if (*pskb) { 21918c2ecf20Sopenharmony_ci err = genlmsg_reply(*pskb, info); 21928c2ecf20Sopenharmony_ci if (err) 21938c2ecf20Sopenharmony_ci return err; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 21968c2ecf20Sopenharmony_ci if (!*pskb) 21978c2ecf20Sopenharmony_ci return -ENOMEM; 21988c2ecf20Sopenharmony_ci return 0; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic int devlink_dpipe_tables_fill(struct genl_info *info, 22028c2ecf20Sopenharmony_ci enum devlink_command cmd, int flags, 22038c2ecf20Sopenharmony_ci struct list_head *dpipe_tables, 22048c2ecf20Sopenharmony_ci const char *table_name) 22058c2ecf20Sopenharmony_ci{ 22068c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 22078c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 22088c2ecf20Sopenharmony_ci struct nlattr *tables_attr; 22098c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 22108c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 22118c2ecf20Sopenharmony_ci bool incomplete; 22128c2ecf20Sopenharmony_ci void *hdr; 22138c2ecf20Sopenharmony_ci int i; 22148c2ecf20Sopenharmony_ci int err; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci table = list_first_entry(dpipe_tables, 22178c2ecf20Sopenharmony_ci struct devlink_dpipe_table, list); 22188c2ecf20Sopenharmony_cistart_again: 22198c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 22208c2ecf20Sopenharmony_ci if (err) 22218c2ecf20Sopenharmony_ci return err; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 22248c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_MULTI, cmd); 22258c2ecf20Sopenharmony_ci if (!hdr) { 22268c2ecf20Sopenharmony_ci nlmsg_free(skb); 22278c2ecf20Sopenharmony_ci return -EMSGSIZE; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(skb, devlink)) 22318c2ecf20Sopenharmony_ci goto nla_put_failure; 22328c2ecf20Sopenharmony_ci tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES); 22338c2ecf20Sopenharmony_ci if (!tables_attr) 22348c2ecf20Sopenharmony_ci goto nla_put_failure; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci i = 0; 22378c2ecf20Sopenharmony_ci incomplete = false; 22388c2ecf20Sopenharmony_ci list_for_each_entry_from(table, dpipe_tables, list) { 22398c2ecf20Sopenharmony_ci if (!table_name) { 22408c2ecf20Sopenharmony_ci err = devlink_dpipe_table_put(skb, table); 22418c2ecf20Sopenharmony_ci if (err) { 22428c2ecf20Sopenharmony_ci if (!i) 22438c2ecf20Sopenharmony_ci goto err_table_put; 22448c2ecf20Sopenharmony_ci incomplete = true; 22458c2ecf20Sopenharmony_ci break; 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci } else { 22488c2ecf20Sopenharmony_ci if (!strcmp(table->name, table_name)) { 22498c2ecf20Sopenharmony_ci err = devlink_dpipe_table_put(skb, table); 22508c2ecf20Sopenharmony_ci if (err) 22518c2ecf20Sopenharmony_ci break; 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci i++; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci nla_nest_end(skb, tables_attr); 22588c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 22598c2ecf20Sopenharmony_ci if (incomplete) 22608c2ecf20Sopenharmony_ci goto start_again; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_cisend_done: 22638c2ecf20Sopenharmony_ci nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 22648c2ecf20Sopenharmony_ci NLMSG_DONE, 0, flags | NLM_F_MULTI); 22658c2ecf20Sopenharmony_ci if (!nlh) { 22668c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 22678c2ecf20Sopenharmony_ci if (err) 22688c2ecf20Sopenharmony_ci return err; 22698c2ecf20Sopenharmony_ci goto send_done; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci return genlmsg_reply(skb, info); 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_cinla_put_failure: 22758c2ecf20Sopenharmony_ci err = -EMSGSIZE; 22768c2ecf20Sopenharmony_cierr_table_put: 22778c2ecf20Sopenharmony_ci nlmsg_free(skb); 22788c2ecf20Sopenharmony_ci return err; 22798c2ecf20Sopenharmony_ci} 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb, 22828c2ecf20Sopenharmony_ci struct genl_info *info) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 22858c2ecf20Sopenharmony_ci const char *table_name = NULL; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]) 22888c2ecf20Sopenharmony_ci table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0, 22918c2ecf20Sopenharmony_ci &devlink->dpipe_table_list, 22928c2ecf20Sopenharmony_ci table_name); 22938c2ecf20Sopenharmony_ci} 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_cistatic int devlink_dpipe_value_put(struct sk_buff *skb, 22968c2ecf20Sopenharmony_ci struct devlink_dpipe_value *value) 22978c2ecf20Sopenharmony_ci{ 22988c2ecf20Sopenharmony_ci if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE, 22998c2ecf20Sopenharmony_ci value->value_size, value->value)) 23008c2ecf20Sopenharmony_ci return -EMSGSIZE; 23018c2ecf20Sopenharmony_ci if (value->mask) 23028c2ecf20Sopenharmony_ci if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK, 23038c2ecf20Sopenharmony_ci value->value_size, value->mask)) 23048c2ecf20Sopenharmony_ci return -EMSGSIZE; 23058c2ecf20Sopenharmony_ci if (value->mapping_valid) 23068c2ecf20Sopenharmony_ci if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING, 23078c2ecf20Sopenharmony_ci value->mapping_value)) 23088c2ecf20Sopenharmony_ci return -EMSGSIZE; 23098c2ecf20Sopenharmony_ci return 0; 23108c2ecf20Sopenharmony_ci} 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_cistatic int devlink_dpipe_action_value_put(struct sk_buff *skb, 23138c2ecf20Sopenharmony_ci struct devlink_dpipe_value *value) 23148c2ecf20Sopenharmony_ci{ 23158c2ecf20Sopenharmony_ci if (!value->action) 23168c2ecf20Sopenharmony_ci return -EINVAL; 23178c2ecf20Sopenharmony_ci if (devlink_dpipe_action_put(skb, value->action)) 23188c2ecf20Sopenharmony_ci return -EMSGSIZE; 23198c2ecf20Sopenharmony_ci if (devlink_dpipe_value_put(skb, value)) 23208c2ecf20Sopenharmony_ci return -EMSGSIZE; 23218c2ecf20Sopenharmony_ci return 0; 23228c2ecf20Sopenharmony_ci} 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_cistatic int devlink_dpipe_action_values_put(struct sk_buff *skb, 23258c2ecf20Sopenharmony_ci struct devlink_dpipe_value *values, 23268c2ecf20Sopenharmony_ci unsigned int values_count) 23278c2ecf20Sopenharmony_ci{ 23288c2ecf20Sopenharmony_ci struct nlattr *action_attr; 23298c2ecf20Sopenharmony_ci int i; 23308c2ecf20Sopenharmony_ci int err; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci for (i = 0; i < values_count; i++) { 23338c2ecf20Sopenharmony_ci action_attr = nla_nest_start_noflag(skb, 23348c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_ACTION_VALUE); 23358c2ecf20Sopenharmony_ci if (!action_attr) 23368c2ecf20Sopenharmony_ci return -EMSGSIZE; 23378c2ecf20Sopenharmony_ci err = devlink_dpipe_action_value_put(skb, &values[i]); 23388c2ecf20Sopenharmony_ci if (err) 23398c2ecf20Sopenharmony_ci goto err_action_value_put; 23408c2ecf20Sopenharmony_ci nla_nest_end(skb, action_attr); 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci return 0; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_cierr_action_value_put: 23458c2ecf20Sopenharmony_ci nla_nest_cancel(skb, action_attr); 23468c2ecf20Sopenharmony_ci return err; 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic int devlink_dpipe_match_value_put(struct sk_buff *skb, 23508c2ecf20Sopenharmony_ci struct devlink_dpipe_value *value) 23518c2ecf20Sopenharmony_ci{ 23528c2ecf20Sopenharmony_ci if (!value->match) 23538c2ecf20Sopenharmony_ci return -EINVAL; 23548c2ecf20Sopenharmony_ci if (devlink_dpipe_match_put(skb, value->match)) 23558c2ecf20Sopenharmony_ci return -EMSGSIZE; 23568c2ecf20Sopenharmony_ci if (devlink_dpipe_value_put(skb, value)) 23578c2ecf20Sopenharmony_ci return -EMSGSIZE; 23588c2ecf20Sopenharmony_ci return 0; 23598c2ecf20Sopenharmony_ci} 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_cistatic int devlink_dpipe_match_values_put(struct sk_buff *skb, 23628c2ecf20Sopenharmony_ci struct devlink_dpipe_value *values, 23638c2ecf20Sopenharmony_ci unsigned int values_count) 23648c2ecf20Sopenharmony_ci{ 23658c2ecf20Sopenharmony_ci struct nlattr *match_attr; 23668c2ecf20Sopenharmony_ci int i; 23678c2ecf20Sopenharmony_ci int err; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci for (i = 0; i < values_count; i++) { 23708c2ecf20Sopenharmony_ci match_attr = nla_nest_start_noflag(skb, 23718c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_MATCH_VALUE); 23728c2ecf20Sopenharmony_ci if (!match_attr) 23738c2ecf20Sopenharmony_ci return -EMSGSIZE; 23748c2ecf20Sopenharmony_ci err = devlink_dpipe_match_value_put(skb, &values[i]); 23758c2ecf20Sopenharmony_ci if (err) 23768c2ecf20Sopenharmony_ci goto err_match_value_put; 23778c2ecf20Sopenharmony_ci nla_nest_end(skb, match_attr); 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci return 0; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_cierr_match_value_put: 23828c2ecf20Sopenharmony_ci nla_nest_cancel(skb, match_attr); 23838c2ecf20Sopenharmony_ci return err; 23848c2ecf20Sopenharmony_ci} 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_cistatic int devlink_dpipe_entry_put(struct sk_buff *skb, 23878c2ecf20Sopenharmony_ci struct devlink_dpipe_entry *entry) 23888c2ecf20Sopenharmony_ci{ 23898c2ecf20Sopenharmony_ci struct nlattr *entry_attr, *matches_attr, *actions_attr; 23908c2ecf20Sopenharmony_ci int err; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY); 23938c2ecf20Sopenharmony_ci if (!entry_attr) 23948c2ecf20Sopenharmony_ci return -EMSGSIZE; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index, 23978c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 23988c2ecf20Sopenharmony_ci goto nla_put_failure; 23998c2ecf20Sopenharmony_ci if (entry->counter_valid) 24008c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER, 24018c2ecf20Sopenharmony_ci entry->counter, DEVLINK_ATTR_PAD)) 24028c2ecf20Sopenharmony_ci goto nla_put_failure; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci matches_attr = nla_nest_start_noflag(skb, 24058c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES); 24068c2ecf20Sopenharmony_ci if (!matches_attr) 24078c2ecf20Sopenharmony_ci goto nla_put_failure; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci err = devlink_dpipe_match_values_put(skb, entry->match_values, 24108c2ecf20Sopenharmony_ci entry->match_values_count); 24118c2ecf20Sopenharmony_ci if (err) { 24128c2ecf20Sopenharmony_ci nla_nest_cancel(skb, matches_attr); 24138c2ecf20Sopenharmony_ci goto err_match_values_put; 24148c2ecf20Sopenharmony_ci } 24158c2ecf20Sopenharmony_ci nla_nest_end(skb, matches_attr); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci actions_attr = nla_nest_start_noflag(skb, 24188c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES); 24198c2ecf20Sopenharmony_ci if (!actions_attr) 24208c2ecf20Sopenharmony_ci goto nla_put_failure; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci err = devlink_dpipe_action_values_put(skb, entry->action_values, 24238c2ecf20Sopenharmony_ci entry->action_values_count); 24248c2ecf20Sopenharmony_ci if (err) { 24258c2ecf20Sopenharmony_ci nla_nest_cancel(skb, actions_attr); 24268c2ecf20Sopenharmony_ci goto err_action_values_put; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci nla_nest_end(skb, actions_attr); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci nla_nest_end(skb, entry_attr); 24318c2ecf20Sopenharmony_ci return 0; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_cinla_put_failure: 24348c2ecf20Sopenharmony_ci err = -EMSGSIZE; 24358c2ecf20Sopenharmony_cierr_match_values_put: 24368c2ecf20Sopenharmony_cierr_action_values_put: 24378c2ecf20Sopenharmony_ci nla_nest_cancel(skb, entry_attr); 24388c2ecf20Sopenharmony_ci return err; 24398c2ecf20Sopenharmony_ci} 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_cistatic struct devlink_dpipe_table * 24428c2ecf20Sopenharmony_cidevlink_dpipe_table_find(struct list_head *dpipe_tables, 24438c2ecf20Sopenharmony_ci const char *table_name, struct devlink *devlink) 24448c2ecf20Sopenharmony_ci{ 24458c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 24468c2ecf20Sopenharmony_ci list_for_each_entry_rcu(table, dpipe_tables, list, 24478c2ecf20Sopenharmony_ci lockdep_is_held(&devlink->lock)) { 24488c2ecf20Sopenharmony_ci if (!strcmp(table->name, table_name)) 24498c2ecf20Sopenharmony_ci return table; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci return NULL; 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci struct devlink *devlink; 24578c2ecf20Sopenharmony_ci int err; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb, 24608c2ecf20Sopenharmony_ci dump_ctx->info); 24618c2ecf20Sopenharmony_ci if (err) 24628c2ecf20Sopenharmony_ci return err; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci dump_ctx->hdr = genlmsg_put(dump_ctx->skb, 24658c2ecf20Sopenharmony_ci dump_ctx->info->snd_portid, 24668c2ecf20Sopenharmony_ci dump_ctx->info->snd_seq, 24678c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_MULTI, 24688c2ecf20Sopenharmony_ci dump_ctx->cmd); 24698c2ecf20Sopenharmony_ci if (!dump_ctx->hdr) 24708c2ecf20Sopenharmony_ci goto nla_put_failure; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci devlink = dump_ctx->info->user_ptr[0]; 24738c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(dump_ctx->skb, devlink)) 24748c2ecf20Sopenharmony_ci goto nla_put_failure; 24758c2ecf20Sopenharmony_ci dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb, 24768c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_ENTRIES); 24778c2ecf20Sopenharmony_ci if (!dump_ctx->nest) 24788c2ecf20Sopenharmony_ci goto nla_put_failure; 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_cinla_put_failure: 24828c2ecf20Sopenharmony_ci nlmsg_free(dump_ctx->skb); 24838c2ecf20Sopenharmony_ci return -EMSGSIZE; 24848c2ecf20Sopenharmony_ci} 24858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare); 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx, 24888c2ecf20Sopenharmony_ci struct devlink_dpipe_entry *entry) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci return devlink_dpipe_entry_put(dump_ctx->skb, entry); 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci nla_nest_end(dump_ctx->skb, dump_ctx->nest); 24978c2ecf20Sopenharmony_ci genlmsg_end(dump_ctx->skb, dump_ctx->hdr); 24988c2ecf20Sopenharmony_ci return 0; 24998c2ecf20Sopenharmony_ci} 25008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close); 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_civoid devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry) 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci{ 25058c2ecf20Sopenharmony_ci unsigned int value_count, value_index; 25068c2ecf20Sopenharmony_ci struct devlink_dpipe_value *value; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci value = entry->action_values; 25098c2ecf20Sopenharmony_ci value_count = entry->action_values_count; 25108c2ecf20Sopenharmony_ci for (value_index = 0; value_index < value_count; value_index++) { 25118c2ecf20Sopenharmony_ci kfree(value[value_index].value); 25128c2ecf20Sopenharmony_ci kfree(value[value_index].mask); 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci value = entry->match_values; 25168c2ecf20Sopenharmony_ci value_count = entry->match_values_count; 25178c2ecf20Sopenharmony_ci for (value_index = 0; value_index < value_count; value_index++) { 25188c2ecf20Sopenharmony_ci kfree(value[value_index].value); 25198c2ecf20Sopenharmony_ci kfree(value[value_index].mask); 25208c2ecf20Sopenharmony_ci } 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_entry_clear); 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_cistatic int devlink_dpipe_entries_fill(struct genl_info *info, 25258c2ecf20Sopenharmony_ci enum devlink_command cmd, int flags, 25268c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table) 25278c2ecf20Sopenharmony_ci{ 25288c2ecf20Sopenharmony_ci struct devlink_dpipe_dump_ctx dump_ctx; 25298c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 25308c2ecf20Sopenharmony_ci int err; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci dump_ctx.skb = NULL; 25338c2ecf20Sopenharmony_ci dump_ctx.cmd = cmd; 25348c2ecf20Sopenharmony_ci dump_ctx.info = info; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci err = table->table_ops->entries_dump(table->priv, 25378c2ecf20Sopenharmony_ci table->counters_enabled, 25388c2ecf20Sopenharmony_ci &dump_ctx); 25398c2ecf20Sopenharmony_ci if (err) 25408c2ecf20Sopenharmony_ci return err; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_cisend_done: 25438c2ecf20Sopenharmony_ci nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq, 25448c2ecf20Sopenharmony_ci NLMSG_DONE, 0, flags | NLM_F_MULTI); 25458c2ecf20Sopenharmony_ci if (!nlh) { 25468c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info); 25478c2ecf20Sopenharmony_ci if (err) 25488c2ecf20Sopenharmony_ci return err; 25498c2ecf20Sopenharmony_ci goto send_done; 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci return genlmsg_reply(dump_ctx.skb, info); 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb, 25558c2ecf20Sopenharmony_ci struct genl_info *info) 25568c2ecf20Sopenharmony_ci{ 25578c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 25588c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 25598c2ecf20Sopenharmony_ci const char *table_name; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]) 25628c2ecf20Sopenharmony_ci return -EINVAL; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 25658c2ecf20Sopenharmony_ci table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 25668c2ecf20Sopenharmony_ci table_name, devlink); 25678c2ecf20Sopenharmony_ci if (!table) 25688c2ecf20Sopenharmony_ci return -EINVAL; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci if (!table->table_ops->entries_dump) 25718c2ecf20Sopenharmony_ci return -EINVAL; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET, 25748c2ecf20Sopenharmony_ci 0, table); 25758c2ecf20Sopenharmony_ci} 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_cistatic int devlink_dpipe_fields_put(struct sk_buff *skb, 25788c2ecf20Sopenharmony_ci const struct devlink_dpipe_header *header) 25798c2ecf20Sopenharmony_ci{ 25808c2ecf20Sopenharmony_ci struct devlink_dpipe_field *field; 25818c2ecf20Sopenharmony_ci struct nlattr *field_attr; 25828c2ecf20Sopenharmony_ci int i; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci for (i = 0; i < header->fields_count; i++) { 25858c2ecf20Sopenharmony_ci field = &header->fields[i]; 25868c2ecf20Sopenharmony_ci field_attr = nla_nest_start_noflag(skb, 25878c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_FIELD); 25888c2ecf20Sopenharmony_ci if (!field_attr) 25898c2ecf20Sopenharmony_ci return -EMSGSIZE; 25908c2ecf20Sopenharmony_ci if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) || 25918c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 25928c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) || 25938c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type)) 25948c2ecf20Sopenharmony_ci goto nla_put_failure; 25958c2ecf20Sopenharmony_ci nla_nest_end(skb, field_attr); 25968c2ecf20Sopenharmony_ci } 25978c2ecf20Sopenharmony_ci return 0; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_cinla_put_failure: 26008c2ecf20Sopenharmony_ci nla_nest_cancel(skb, field_attr); 26018c2ecf20Sopenharmony_ci return -EMSGSIZE; 26028c2ecf20Sopenharmony_ci} 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_cistatic int devlink_dpipe_header_put(struct sk_buff *skb, 26058c2ecf20Sopenharmony_ci struct devlink_dpipe_header *header) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci struct nlattr *fields_attr, *header_attr; 26088c2ecf20Sopenharmony_ci int err; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER); 26118c2ecf20Sopenharmony_ci if (!header_attr) 26128c2ecf20Sopenharmony_ci return -EMSGSIZE; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) || 26158c2ecf20Sopenharmony_ci nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 26168c2ecf20Sopenharmony_ci nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 26178c2ecf20Sopenharmony_ci goto nla_put_failure; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci fields_attr = nla_nest_start_noflag(skb, 26208c2ecf20Sopenharmony_ci DEVLINK_ATTR_DPIPE_HEADER_FIELDS); 26218c2ecf20Sopenharmony_ci if (!fields_attr) 26228c2ecf20Sopenharmony_ci goto nla_put_failure; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci err = devlink_dpipe_fields_put(skb, header); 26258c2ecf20Sopenharmony_ci if (err) { 26268c2ecf20Sopenharmony_ci nla_nest_cancel(skb, fields_attr); 26278c2ecf20Sopenharmony_ci goto nla_put_failure; 26288c2ecf20Sopenharmony_ci } 26298c2ecf20Sopenharmony_ci nla_nest_end(skb, fields_attr); 26308c2ecf20Sopenharmony_ci nla_nest_end(skb, header_attr); 26318c2ecf20Sopenharmony_ci return 0; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_cinla_put_failure: 26348c2ecf20Sopenharmony_ci err = -EMSGSIZE; 26358c2ecf20Sopenharmony_ci nla_nest_cancel(skb, header_attr); 26368c2ecf20Sopenharmony_ci return err; 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_cistatic int devlink_dpipe_headers_fill(struct genl_info *info, 26408c2ecf20Sopenharmony_ci enum devlink_command cmd, int flags, 26418c2ecf20Sopenharmony_ci struct devlink_dpipe_headers * 26428c2ecf20Sopenharmony_ci dpipe_headers) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 26458c2ecf20Sopenharmony_ci struct nlattr *headers_attr; 26468c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 26478c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 26488c2ecf20Sopenharmony_ci void *hdr; 26498c2ecf20Sopenharmony_ci int i, j; 26508c2ecf20Sopenharmony_ci int err; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci i = 0; 26538c2ecf20Sopenharmony_cistart_again: 26548c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 26558c2ecf20Sopenharmony_ci if (err) 26568c2ecf20Sopenharmony_ci return err; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 26598c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_MULTI, cmd); 26608c2ecf20Sopenharmony_ci if (!hdr) { 26618c2ecf20Sopenharmony_ci nlmsg_free(skb); 26628c2ecf20Sopenharmony_ci return -EMSGSIZE; 26638c2ecf20Sopenharmony_ci } 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(skb, devlink)) 26668c2ecf20Sopenharmony_ci goto nla_put_failure; 26678c2ecf20Sopenharmony_ci headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS); 26688c2ecf20Sopenharmony_ci if (!headers_attr) 26698c2ecf20Sopenharmony_ci goto nla_put_failure; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci j = 0; 26728c2ecf20Sopenharmony_ci for (; i < dpipe_headers->headers_count; i++) { 26738c2ecf20Sopenharmony_ci err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]); 26748c2ecf20Sopenharmony_ci if (err) { 26758c2ecf20Sopenharmony_ci if (!j) 26768c2ecf20Sopenharmony_ci goto err_table_put; 26778c2ecf20Sopenharmony_ci break; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci j++; 26808c2ecf20Sopenharmony_ci } 26818c2ecf20Sopenharmony_ci nla_nest_end(skb, headers_attr); 26828c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 26838c2ecf20Sopenharmony_ci if (i != dpipe_headers->headers_count) 26848c2ecf20Sopenharmony_ci goto start_again; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_cisend_done: 26878c2ecf20Sopenharmony_ci nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 26888c2ecf20Sopenharmony_ci NLMSG_DONE, 0, flags | NLM_F_MULTI); 26898c2ecf20Sopenharmony_ci if (!nlh) { 26908c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 26918c2ecf20Sopenharmony_ci if (err) 26928c2ecf20Sopenharmony_ci return err; 26938c2ecf20Sopenharmony_ci goto send_done; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci return genlmsg_reply(skb, info); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_cinla_put_failure: 26988c2ecf20Sopenharmony_ci err = -EMSGSIZE; 26998c2ecf20Sopenharmony_cierr_table_put: 27008c2ecf20Sopenharmony_ci nlmsg_free(skb); 27018c2ecf20Sopenharmony_ci return err; 27028c2ecf20Sopenharmony_ci} 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb, 27058c2ecf20Sopenharmony_ci struct genl_info *info) 27068c2ecf20Sopenharmony_ci{ 27078c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci if (!devlink->dpipe_headers) 27108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27118c2ecf20Sopenharmony_ci return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET, 27128c2ecf20Sopenharmony_ci 0, devlink->dpipe_headers); 27138c2ecf20Sopenharmony_ci} 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_cistatic int devlink_dpipe_table_counters_set(struct devlink *devlink, 27168c2ecf20Sopenharmony_ci const char *table_name, 27178c2ecf20Sopenharmony_ci bool enable) 27188c2ecf20Sopenharmony_ci{ 27198c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 27228c2ecf20Sopenharmony_ci table_name, devlink); 27238c2ecf20Sopenharmony_ci if (!table) 27248c2ecf20Sopenharmony_ci return -EINVAL; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci if (table->counter_control_extern) 27278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci if (!(table->counters_enabled ^ enable)) 27308c2ecf20Sopenharmony_ci return 0; 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci table->counters_enabled = enable; 27338c2ecf20Sopenharmony_ci if (table->table_ops->counters_set_update) 27348c2ecf20Sopenharmony_ci table->table_ops->counters_set_update(table->priv, enable); 27358c2ecf20Sopenharmony_ci return 0; 27368c2ecf20Sopenharmony_ci} 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb, 27398c2ecf20Sopenharmony_ci struct genl_info *info) 27408c2ecf20Sopenharmony_ci{ 27418c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 27428c2ecf20Sopenharmony_ci const char *table_name; 27438c2ecf20Sopenharmony_ci bool counters_enable; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] || 27468c2ecf20Sopenharmony_ci !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) 27478c2ecf20Sopenharmony_ci return -EINVAL; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 27508c2ecf20Sopenharmony_ci counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci return devlink_dpipe_table_counters_set(devlink, table_name, 27538c2ecf20Sopenharmony_ci counters_enable); 27548c2ecf20Sopenharmony_ci} 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_cistatic struct devlink_resource * 27578c2ecf20Sopenharmony_cidevlink_resource_find(struct devlink *devlink, 27588c2ecf20Sopenharmony_ci struct devlink_resource *resource, u64 resource_id) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci struct list_head *resource_list; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci if (resource) 27638c2ecf20Sopenharmony_ci resource_list = &resource->resource_list; 27648c2ecf20Sopenharmony_ci else 27658c2ecf20Sopenharmony_ci resource_list = &devlink->resource_list; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci list_for_each_entry(resource, resource_list, list) { 27688c2ecf20Sopenharmony_ci struct devlink_resource *child_resource; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci if (resource->id == resource_id) 27718c2ecf20Sopenharmony_ci return resource; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci child_resource = devlink_resource_find(devlink, resource, 27748c2ecf20Sopenharmony_ci resource_id); 27758c2ecf20Sopenharmony_ci if (child_resource) 27768c2ecf20Sopenharmony_ci return child_resource; 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci return NULL; 27798c2ecf20Sopenharmony_ci} 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_cistatic void 27828c2ecf20Sopenharmony_cidevlink_resource_validate_children(struct devlink_resource *resource) 27838c2ecf20Sopenharmony_ci{ 27848c2ecf20Sopenharmony_ci struct devlink_resource *child_resource; 27858c2ecf20Sopenharmony_ci bool size_valid = true; 27868c2ecf20Sopenharmony_ci u64 parts_size = 0; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci if (list_empty(&resource->resource_list)) 27898c2ecf20Sopenharmony_ci goto out; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci list_for_each_entry(child_resource, &resource->resource_list, list) 27928c2ecf20Sopenharmony_ci parts_size += child_resource->size_new; 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (parts_size > resource->size_new) 27958c2ecf20Sopenharmony_ci size_valid = false; 27968c2ecf20Sopenharmony_ciout: 27978c2ecf20Sopenharmony_ci resource->size_valid = size_valid; 27988c2ecf20Sopenharmony_ci} 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_cistatic int 28018c2ecf20Sopenharmony_cidevlink_resource_validate_size(struct devlink_resource *resource, u64 size, 28028c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 28038c2ecf20Sopenharmony_ci{ 28048c2ecf20Sopenharmony_ci u64 reminder; 28058c2ecf20Sopenharmony_ci int err = 0; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci if (size > resource->size_params.size_max) { 28088c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum"); 28098c2ecf20Sopenharmony_ci err = -EINVAL; 28108c2ecf20Sopenharmony_ci } 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci if (size < resource->size_params.size_min) { 28138c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum"); 28148c2ecf20Sopenharmony_ci err = -EINVAL; 28158c2ecf20Sopenharmony_ci } 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci div64_u64_rem(size, resource->size_params.size_granularity, &reminder); 28188c2ecf20Sopenharmony_ci if (reminder) { 28198c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Wrong granularity"); 28208c2ecf20Sopenharmony_ci err = -EINVAL; 28218c2ecf20Sopenharmony_ci } 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci return err; 28248c2ecf20Sopenharmony_ci} 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_resource_set(struct sk_buff *skb, 28278c2ecf20Sopenharmony_ci struct genl_info *info) 28288c2ecf20Sopenharmony_ci{ 28298c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 28308c2ecf20Sopenharmony_ci struct devlink_resource *resource; 28318c2ecf20Sopenharmony_ci u64 resource_id; 28328c2ecf20Sopenharmony_ci u64 size; 28338c2ecf20Sopenharmony_ci int err; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] || 28368c2ecf20Sopenharmony_ci !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]) 28378c2ecf20Sopenharmony_ci return -EINVAL; 28388c2ecf20Sopenharmony_ci resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci resource = devlink_resource_find(devlink, NULL, resource_id); 28418c2ecf20Sopenharmony_ci if (!resource) 28428c2ecf20Sopenharmony_ci return -EINVAL; 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]); 28458c2ecf20Sopenharmony_ci err = devlink_resource_validate_size(resource, size, info->extack); 28468c2ecf20Sopenharmony_ci if (err) 28478c2ecf20Sopenharmony_ci return err; 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci resource->size_new = size; 28508c2ecf20Sopenharmony_ci devlink_resource_validate_children(resource); 28518c2ecf20Sopenharmony_ci if (resource->parent) 28528c2ecf20Sopenharmony_ci devlink_resource_validate_children(resource->parent); 28538c2ecf20Sopenharmony_ci return 0; 28548c2ecf20Sopenharmony_ci} 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_cistatic int 28578c2ecf20Sopenharmony_cidevlink_resource_size_params_put(struct devlink_resource *resource, 28588c2ecf20Sopenharmony_ci struct sk_buff *skb) 28598c2ecf20Sopenharmony_ci{ 28608c2ecf20Sopenharmony_ci struct devlink_resource_size_params *size_params; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci size_params = &resource->size_params; 28638c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN, 28648c2ecf20Sopenharmony_ci size_params->size_granularity, DEVLINK_ATTR_PAD) || 28658c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX, 28668c2ecf20Sopenharmony_ci size_params->size_max, DEVLINK_ATTR_PAD) || 28678c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN, 28688c2ecf20Sopenharmony_ci size_params->size_min, DEVLINK_ATTR_PAD) || 28698c2ecf20Sopenharmony_ci nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit)) 28708c2ecf20Sopenharmony_ci return -EMSGSIZE; 28718c2ecf20Sopenharmony_ci return 0; 28728c2ecf20Sopenharmony_ci} 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_cistatic int devlink_resource_occ_put(struct devlink_resource *resource, 28758c2ecf20Sopenharmony_ci struct sk_buff *skb) 28768c2ecf20Sopenharmony_ci{ 28778c2ecf20Sopenharmony_ci if (!resource->occ_get) 28788c2ecf20Sopenharmony_ci return 0; 28798c2ecf20Sopenharmony_ci return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC, 28808c2ecf20Sopenharmony_ci resource->occ_get(resource->occ_get_priv), 28818c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD); 28828c2ecf20Sopenharmony_ci} 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_cistatic int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb, 28858c2ecf20Sopenharmony_ci struct devlink_resource *resource) 28868c2ecf20Sopenharmony_ci{ 28878c2ecf20Sopenharmony_ci struct devlink_resource *child_resource; 28888c2ecf20Sopenharmony_ci struct nlattr *child_resource_attr; 28898c2ecf20Sopenharmony_ci struct nlattr *resource_attr; 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE); 28928c2ecf20Sopenharmony_ci if (!resource_attr) 28938c2ecf20Sopenharmony_ci return -EMSGSIZE; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) || 28968c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size, 28978c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD) || 28988c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id, 28998c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 29008c2ecf20Sopenharmony_ci goto nla_put_failure; 29018c2ecf20Sopenharmony_ci if (resource->size != resource->size_new) 29028c2ecf20Sopenharmony_ci nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW, 29038c2ecf20Sopenharmony_ci resource->size_new, DEVLINK_ATTR_PAD); 29048c2ecf20Sopenharmony_ci if (devlink_resource_occ_put(resource, skb)) 29058c2ecf20Sopenharmony_ci goto nla_put_failure; 29068c2ecf20Sopenharmony_ci if (devlink_resource_size_params_put(resource, skb)) 29078c2ecf20Sopenharmony_ci goto nla_put_failure; 29088c2ecf20Sopenharmony_ci if (list_empty(&resource->resource_list)) 29098c2ecf20Sopenharmony_ci goto out; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID, 29128c2ecf20Sopenharmony_ci resource->size_valid)) 29138c2ecf20Sopenharmony_ci goto nla_put_failure; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci child_resource_attr = nla_nest_start_noflag(skb, 29168c2ecf20Sopenharmony_ci DEVLINK_ATTR_RESOURCE_LIST); 29178c2ecf20Sopenharmony_ci if (!child_resource_attr) 29188c2ecf20Sopenharmony_ci goto nla_put_failure; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci list_for_each_entry(child_resource, &resource->resource_list, list) { 29218c2ecf20Sopenharmony_ci if (devlink_resource_put(devlink, skb, child_resource)) 29228c2ecf20Sopenharmony_ci goto resource_put_failure; 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci nla_nest_end(skb, child_resource_attr); 29268c2ecf20Sopenharmony_ciout: 29278c2ecf20Sopenharmony_ci nla_nest_end(skb, resource_attr); 29288c2ecf20Sopenharmony_ci return 0; 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ciresource_put_failure: 29318c2ecf20Sopenharmony_ci nla_nest_cancel(skb, child_resource_attr); 29328c2ecf20Sopenharmony_cinla_put_failure: 29338c2ecf20Sopenharmony_ci nla_nest_cancel(skb, resource_attr); 29348c2ecf20Sopenharmony_ci return -EMSGSIZE; 29358c2ecf20Sopenharmony_ci} 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_cistatic int devlink_resource_fill(struct genl_info *info, 29388c2ecf20Sopenharmony_ci enum devlink_command cmd, int flags) 29398c2ecf20Sopenharmony_ci{ 29408c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 29418c2ecf20Sopenharmony_ci struct devlink_resource *resource; 29428c2ecf20Sopenharmony_ci struct nlattr *resources_attr; 29438c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 29448c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 29458c2ecf20Sopenharmony_ci bool incomplete; 29468c2ecf20Sopenharmony_ci void *hdr; 29478c2ecf20Sopenharmony_ci int i; 29488c2ecf20Sopenharmony_ci int err; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci resource = list_first_entry(&devlink->resource_list, 29518c2ecf20Sopenharmony_ci struct devlink_resource, list); 29528c2ecf20Sopenharmony_cistart_again: 29538c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 29548c2ecf20Sopenharmony_ci if (err) 29558c2ecf20Sopenharmony_ci return err; 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 29588c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_MULTI, cmd); 29598c2ecf20Sopenharmony_ci if (!hdr) { 29608c2ecf20Sopenharmony_ci nlmsg_free(skb); 29618c2ecf20Sopenharmony_ci return -EMSGSIZE; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(skb, devlink)) 29658c2ecf20Sopenharmony_ci goto nla_put_failure; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci resources_attr = nla_nest_start_noflag(skb, 29688c2ecf20Sopenharmony_ci DEVLINK_ATTR_RESOURCE_LIST); 29698c2ecf20Sopenharmony_ci if (!resources_attr) 29708c2ecf20Sopenharmony_ci goto nla_put_failure; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci incomplete = false; 29738c2ecf20Sopenharmony_ci i = 0; 29748c2ecf20Sopenharmony_ci list_for_each_entry_from(resource, &devlink->resource_list, list) { 29758c2ecf20Sopenharmony_ci err = devlink_resource_put(devlink, skb, resource); 29768c2ecf20Sopenharmony_ci if (err) { 29778c2ecf20Sopenharmony_ci if (!i) 29788c2ecf20Sopenharmony_ci goto err_resource_put; 29798c2ecf20Sopenharmony_ci incomplete = true; 29808c2ecf20Sopenharmony_ci break; 29818c2ecf20Sopenharmony_ci } 29828c2ecf20Sopenharmony_ci i++; 29838c2ecf20Sopenharmony_ci } 29848c2ecf20Sopenharmony_ci nla_nest_end(skb, resources_attr); 29858c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 29868c2ecf20Sopenharmony_ci if (incomplete) 29878c2ecf20Sopenharmony_ci goto start_again; 29888c2ecf20Sopenharmony_cisend_done: 29898c2ecf20Sopenharmony_ci nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 29908c2ecf20Sopenharmony_ci NLMSG_DONE, 0, flags | NLM_F_MULTI); 29918c2ecf20Sopenharmony_ci if (!nlh) { 29928c2ecf20Sopenharmony_ci err = devlink_dpipe_send_and_alloc_skb(&skb, info); 29938c2ecf20Sopenharmony_ci if (err) 29948c2ecf20Sopenharmony_ci return err; 29958c2ecf20Sopenharmony_ci goto send_done; 29968c2ecf20Sopenharmony_ci } 29978c2ecf20Sopenharmony_ci return genlmsg_reply(skb, info); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_cinla_put_failure: 30008c2ecf20Sopenharmony_ci err = -EMSGSIZE; 30018c2ecf20Sopenharmony_cierr_resource_put: 30028c2ecf20Sopenharmony_ci nlmsg_free(skb); 30038c2ecf20Sopenharmony_ci return err; 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_resource_dump(struct sk_buff *skb, 30078c2ecf20Sopenharmony_ci struct genl_info *info) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci if (list_empty(&devlink->resource_list)) 30128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0); 30158c2ecf20Sopenharmony_ci} 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_cistatic int 30188c2ecf20Sopenharmony_cidevlink_resources_validate(struct devlink *devlink, 30198c2ecf20Sopenharmony_ci struct devlink_resource *resource, 30208c2ecf20Sopenharmony_ci struct genl_info *info) 30218c2ecf20Sopenharmony_ci{ 30228c2ecf20Sopenharmony_ci struct list_head *resource_list; 30238c2ecf20Sopenharmony_ci int err = 0; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (resource) 30268c2ecf20Sopenharmony_ci resource_list = &resource->resource_list; 30278c2ecf20Sopenharmony_ci else 30288c2ecf20Sopenharmony_ci resource_list = &devlink->resource_list; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci list_for_each_entry(resource, resource_list, list) { 30318c2ecf20Sopenharmony_ci if (!resource->size_valid) 30328c2ecf20Sopenharmony_ci return -EINVAL; 30338c2ecf20Sopenharmony_ci err = devlink_resources_validate(devlink, resource, info); 30348c2ecf20Sopenharmony_ci if (err) 30358c2ecf20Sopenharmony_ci return err; 30368c2ecf20Sopenharmony_ci } 30378c2ecf20Sopenharmony_ci return err; 30388c2ecf20Sopenharmony_ci} 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_cistatic struct net *devlink_netns_get(struct sk_buff *skb, 30418c2ecf20Sopenharmony_ci struct genl_info *info) 30428c2ecf20Sopenharmony_ci{ 30438c2ecf20Sopenharmony_ci struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID]; 30448c2ecf20Sopenharmony_ci struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD]; 30458c2ecf20Sopenharmony_ci struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID]; 30468c2ecf20Sopenharmony_ci struct net *net; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) { 30498c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified"); 30508c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci if (netns_pid_attr) { 30548c2ecf20Sopenharmony_ci net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr)); 30558c2ecf20Sopenharmony_ci } else if (netns_fd_attr) { 30568c2ecf20Sopenharmony_ci net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr)); 30578c2ecf20Sopenharmony_ci } else if (netns_id_attr) { 30588c2ecf20Sopenharmony_ci net = get_net_ns_by_id(sock_net(skb->sk), 30598c2ecf20Sopenharmony_ci nla_get_u32(netns_id_attr)); 30608c2ecf20Sopenharmony_ci if (!net) 30618c2ecf20Sopenharmony_ci net = ERR_PTR(-EINVAL); 30628c2ecf20Sopenharmony_ci } else { 30638c2ecf20Sopenharmony_ci WARN_ON(1); 30648c2ecf20Sopenharmony_ci net = ERR_PTR(-EINVAL); 30658c2ecf20Sopenharmony_ci } 30668c2ecf20Sopenharmony_ci if (IS_ERR(net)) { 30678c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace"); 30688c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 30698c2ecf20Sopenharmony_ci } 30708c2ecf20Sopenharmony_ci if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { 30718c2ecf20Sopenharmony_ci put_net(net); 30728c2ecf20Sopenharmony_ci return ERR_PTR(-EPERM); 30738c2ecf20Sopenharmony_ci } 30748c2ecf20Sopenharmony_ci return net; 30758c2ecf20Sopenharmony_ci} 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_cistatic void devlink_param_notify(struct devlink *devlink, 30788c2ecf20Sopenharmony_ci unsigned int port_index, 30798c2ecf20Sopenharmony_ci struct devlink_param_item *param_item, 30808c2ecf20Sopenharmony_ci enum devlink_command cmd); 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_cistatic void devlink_ns_change_notify(struct devlink *devlink, 30838c2ecf20Sopenharmony_ci struct net *dest_net, struct net *curr_net, 30848c2ecf20Sopenharmony_ci bool new) 30858c2ecf20Sopenharmony_ci{ 30868c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 30878c2ecf20Sopenharmony_ci enum devlink_command cmd; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci /* Userspace needs to be notified about devlink objects 30908c2ecf20Sopenharmony_ci * removed from original and entering new network namespace. 30918c2ecf20Sopenharmony_ci * The rest of the devlink objects are re-created during 30928c2ecf20Sopenharmony_ci * reload process so the notifications are generated separatelly. 30938c2ecf20Sopenharmony_ci */ 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (!dest_net || net_eq(dest_net, curr_net)) 30968c2ecf20Sopenharmony_ci return; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci if (new) 30998c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_NEW); 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci cmd = new ? DEVLINK_CMD_PARAM_NEW : DEVLINK_CMD_PARAM_DEL; 31028c2ecf20Sopenharmony_ci list_for_each_entry(param_item, &devlink->param_list, list) 31038c2ecf20Sopenharmony_ci devlink_param_notify(devlink, 0, param_item, cmd); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci if (!new) 31068c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_DEL); 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_cistatic bool devlink_reload_supported(const struct devlink_ops *ops) 31108c2ecf20Sopenharmony_ci{ 31118c2ecf20Sopenharmony_ci return ops->reload_down && ops->reload_up; 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic void devlink_reload_failed_set(struct devlink *devlink, 31158c2ecf20Sopenharmony_ci bool reload_failed) 31168c2ecf20Sopenharmony_ci{ 31178c2ecf20Sopenharmony_ci if (devlink->reload_failed == reload_failed) 31188c2ecf20Sopenharmony_ci return; 31198c2ecf20Sopenharmony_ci devlink->reload_failed = reload_failed; 31208c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_NEW); 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_cibool devlink_is_reload_failed(const struct devlink *devlink) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci return devlink->reload_failed; 31268c2ecf20Sopenharmony_ci} 31278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_is_reload_failed); 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_cistatic void 31308c2ecf20Sopenharmony_ci__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats, 31318c2ecf20Sopenharmony_ci enum devlink_reload_limit limit, u32 actions_performed) 31328c2ecf20Sopenharmony_ci{ 31338c2ecf20Sopenharmony_ci unsigned long actions = actions_performed; 31348c2ecf20Sopenharmony_ci int stat_idx; 31358c2ecf20Sopenharmony_ci int action; 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) { 31388c2ecf20Sopenharmony_ci stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action; 31398c2ecf20Sopenharmony_ci reload_stats[stat_idx]++; 31408c2ecf20Sopenharmony_ci } 31418c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_NEW); 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_cistatic void 31458c2ecf20Sopenharmony_cidevlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit, 31468c2ecf20Sopenharmony_ci u32 actions_performed) 31478c2ecf20Sopenharmony_ci{ 31488c2ecf20Sopenharmony_ci __devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit, 31498c2ecf20Sopenharmony_ci actions_performed); 31508c2ecf20Sopenharmony_ci} 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci/** 31538c2ecf20Sopenharmony_ci * devlink_remote_reload_actions_performed - Update devlink on reload actions 31548c2ecf20Sopenharmony_ci * performed which are not a direct result of devlink reload call. 31558c2ecf20Sopenharmony_ci * 31568c2ecf20Sopenharmony_ci * This should be called by a driver after performing reload actions in case it was not 31578c2ecf20Sopenharmony_ci * a result of devlink reload call. For example fw_activate was performed as a result 31588c2ecf20Sopenharmony_ci * of devlink reload triggered fw_activate on another host. 31598c2ecf20Sopenharmony_ci * The motivation for this function is to keep data on reload actions performed on this 31608c2ecf20Sopenharmony_ci * function whether it was done due to direct devlink reload call or not. 31618c2ecf20Sopenharmony_ci * 31628c2ecf20Sopenharmony_ci * @devlink: devlink 31638c2ecf20Sopenharmony_ci * @limit: reload limit 31648c2ecf20Sopenharmony_ci * @actions_performed: bitmask of actions performed 31658c2ecf20Sopenharmony_ci */ 31668c2ecf20Sopenharmony_civoid devlink_remote_reload_actions_performed(struct devlink *devlink, 31678c2ecf20Sopenharmony_ci enum devlink_reload_limit limit, 31688c2ecf20Sopenharmony_ci u32 actions_performed) 31698c2ecf20Sopenharmony_ci{ 31708c2ecf20Sopenharmony_ci if (WARN_ON(!actions_performed || 31718c2ecf20Sopenharmony_ci actions_performed & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || 31728c2ecf20Sopenharmony_ci actions_performed >= BIT(__DEVLINK_RELOAD_ACTION_MAX) || 31738c2ecf20Sopenharmony_ci limit > DEVLINK_RELOAD_LIMIT_MAX)) 31748c2ecf20Sopenharmony_ci return; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci __devlink_reload_stats_update(devlink, devlink->stats.remote_reload_stats, limit, 31778c2ecf20Sopenharmony_ci actions_performed); 31788c2ecf20Sopenharmony_ci} 31798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_remote_reload_actions_performed); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_cistatic int devlink_reload(struct devlink *devlink, struct net *dest_net, 31828c2ecf20Sopenharmony_ci enum devlink_reload_action action, enum devlink_reload_limit limit, 31838c2ecf20Sopenharmony_ci u32 *actions_performed, struct netlink_ext_ack *extack) 31848c2ecf20Sopenharmony_ci{ 31858c2ecf20Sopenharmony_ci u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE]; 31868c2ecf20Sopenharmony_ci struct net *curr_net; 31878c2ecf20Sopenharmony_ci int err; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci if (!devlink->reload_enabled) 31908c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci memcpy(remote_reload_stats, devlink->stats.remote_reload_stats, 31938c2ecf20Sopenharmony_ci sizeof(remote_reload_stats)); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci curr_net = devlink_net(devlink); 31968c2ecf20Sopenharmony_ci devlink_ns_change_notify(devlink, dest_net, curr_net, false); 31978c2ecf20Sopenharmony_ci err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack); 31988c2ecf20Sopenharmony_ci if (err) 31998c2ecf20Sopenharmony_ci return err; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci if (dest_net && !net_eq(dest_net, curr_net)) 32028c2ecf20Sopenharmony_ci __devlink_net_set(devlink, dest_net); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack); 32058c2ecf20Sopenharmony_ci devlink_reload_failed_set(devlink, !!err); 32068c2ecf20Sopenharmony_ci if (err) 32078c2ecf20Sopenharmony_ci return err; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci devlink_ns_change_notify(devlink, dest_net, curr_net, true); 32108c2ecf20Sopenharmony_ci WARN_ON(!(*actions_performed & BIT(action))); 32118c2ecf20Sopenharmony_ci /* Catch driver on updating the remote action within devlink reload */ 32128c2ecf20Sopenharmony_ci WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats, 32138c2ecf20Sopenharmony_ci sizeof(remote_reload_stats))); 32148c2ecf20Sopenharmony_ci devlink_reload_stats_update(devlink, limit, *actions_performed); 32158c2ecf20Sopenharmony_ci return 0; 32168c2ecf20Sopenharmony_ci} 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_cistatic int 32198c2ecf20Sopenharmony_cidevlink_nl_reload_actions_performed_snd(struct devlink *devlink, u32 actions_performed, 32208c2ecf20Sopenharmony_ci enum devlink_command cmd, struct genl_info *info) 32218c2ecf20Sopenharmony_ci{ 32228c2ecf20Sopenharmony_ci struct sk_buff *msg; 32238c2ecf20Sopenharmony_ci void *hdr; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 32268c2ecf20Sopenharmony_ci if (!msg) 32278c2ecf20Sopenharmony_ci return -ENOMEM; 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &devlink_nl_family, 0, cmd); 32308c2ecf20Sopenharmony_ci if (!hdr) 32318c2ecf20Sopenharmony_ci goto free_msg; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 32348c2ecf20Sopenharmony_ci goto nla_put_failure; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed, 32378c2ecf20Sopenharmony_ci actions_performed)) 32388c2ecf20Sopenharmony_ci goto nla_put_failure; 32398c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_cinla_put_failure: 32448c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 32458c2ecf20Sopenharmony_cifree_msg: 32468c2ecf20Sopenharmony_ci nlmsg_free(msg); 32478c2ecf20Sopenharmony_ci return -EMSGSIZE; 32488c2ecf20Sopenharmony_ci} 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) 32518c2ecf20Sopenharmony_ci{ 32528c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 32538c2ecf20Sopenharmony_ci enum devlink_reload_action action; 32548c2ecf20Sopenharmony_ci enum devlink_reload_limit limit; 32558c2ecf20Sopenharmony_ci struct net *dest_net = NULL; 32568c2ecf20Sopenharmony_ci u32 actions_performed; 32578c2ecf20Sopenharmony_ci int err; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci if (!devlink_reload_supported(devlink->ops)) 32608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci err = devlink_resources_validate(devlink, NULL, info); 32638c2ecf20Sopenharmony_ci if (err) { 32648c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed"); 32658c2ecf20Sopenharmony_ci return err; 32668c2ecf20Sopenharmony_ci } 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION]) 32698c2ecf20Sopenharmony_ci action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]); 32708c2ecf20Sopenharmony_ci else 32718c2ecf20Sopenharmony_ci action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci if (!devlink_reload_action_is_supported(devlink, action)) { 32748c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, 32758c2ecf20Sopenharmony_ci "Requested reload action is not supported by the driver"); 32768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci limit = DEVLINK_RELOAD_LIMIT_UNSPEC; 32808c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) { 32818c2ecf20Sopenharmony_ci struct nla_bitfield32 limits; 32828c2ecf20Sopenharmony_ci u32 limits_selected; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]); 32858c2ecf20Sopenharmony_ci limits_selected = limits.value & limits.selector; 32868c2ecf20Sopenharmony_ci if (!limits_selected) { 32878c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Invalid limit selected"); 32888c2ecf20Sopenharmony_ci return -EINVAL; 32898c2ecf20Sopenharmony_ci } 32908c2ecf20Sopenharmony_ci for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++) 32918c2ecf20Sopenharmony_ci if (limits_selected & BIT(limit)) 32928c2ecf20Sopenharmony_ci break; 32938c2ecf20Sopenharmony_ci /* UAPI enables multiselection, but currently it is not used */ 32948c2ecf20Sopenharmony_ci if (limits_selected != BIT(limit)) { 32958c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, 32968c2ecf20Sopenharmony_ci "Multiselection of limit is not supported"); 32978c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32988c2ecf20Sopenharmony_ci } 32998c2ecf20Sopenharmony_ci if (!devlink_reload_limit_is_supported(devlink, limit)) { 33008c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, 33018c2ecf20Sopenharmony_ci "Requested limit is not supported by the driver"); 33028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci if (devlink_reload_combination_is_invalid(action, limit)) { 33058c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, 33068c2ecf20Sopenharmony_ci "Requested limit is invalid for this action"); 33078c2ecf20Sopenharmony_ci return -EINVAL; 33088c2ecf20Sopenharmony_ci } 33098c2ecf20Sopenharmony_ci } 33108c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_NETNS_PID] || 33118c2ecf20Sopenharmony_ci info->attrs[DEVLINK_ATTR_NETNS_FD] || 33128c2ecf20Sopenharmony_ci info->attrs[DEVLINK_ATTR_NETNS_ID]) { 33138c2ecf20Sopenharmony_ci dest_net = devlink_netns_get(skb, info); 33148c2ecf20Sopenharmony_ci if (IS_ERR(dest_net)) 33158c2ecf20Sopenharmony_ci return PTR_ERR(dest_net); 33168c2ecf20Sopenharmony_ci } 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack); 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (dest_net) 33218c2ecf20Sopenharmony_ci put_net(dest_net); 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci if (err) 33248c2ecf20Sopenharmony_ci return err; 33258c2ecf20Sopenharmony_ci /* For backward compatibility generate reply only if attributes used by user */ 33268c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) 33278c2ecf20Sopenharmony_ci return 0; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci return devlink_nl_reload_actions_performed_snd(devlink, actions_performed, 33308c2ecf20Sopenharmony_ci DEVLINK_CMD_RELOAD, info); 33318c2ecf20Sopenharmony_ci} 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_cistatic int devlink_nl_flash_update_fill(struct sk_buff *msg, 33348c2ecf20Sopenharmony_ci struct devlink *devlink, 33358c2ecf20Sopenharmony_ci enum devlink_command cmd, 33368c2ecf20Sopenharmony_ci struct devlink_flash_notify *params) 33378c2ecf20Sopenharmony_ci{ 33388c2ecf20Sopenharmony_ci void *hdr; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd); 33418c2ecf20Sopenharmony_ci if (!hdr) 33428c2ecf20Sopenharmony_ci return -EMSGSIZE; 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 33458c2ecf20Sopenharmony_ci goto nla_put_failure; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS) 33488c2ecf20Sopenharmony_ci goto out; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci if (params->status_msg && 33518c2ecf20Sopenharmony_ci nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG, 33528c2ecf20Sopenharmony_ci params->status_msg)) 33538c2ecf20Sopenharmony_ci goto nla_put_failure; 33548c2ecf20Sopenharmony_ci if (params->component && 33558c2ecf20Sopenharmony_ci nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, 33568c2ecf20Sopenharmony_ci params->component)) 33578c2ecf20Sopenharmony_ci goto nla_put_failure; 33588c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE, 33598c2ecf20Sopenharmony_ci params->done, DEVLINK_ATTR_PAD)) 33608c2ecf20Sopenharmony_ci goto nla_put_failure; 33618c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL, 33628c2ecf20Sopenharmony_ci params->total, DEVLINK_ATTR_PAD)) 33638c2ecf20Sopenharmony_ci goto nla_put_failure; 33648c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT, 33658c2ecf20Sopenharmony_ci params->timeout, DEVLINK_ATTR_PAD)) 33668c2ecf20Sopenharmony_ci goto nla_put_failure; 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ciout: 33698c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 33708c2ecf20Sopenharmony_ci return 0; 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_cinla_put_failure: 33738c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 33748c2ecf20Sopenharmony_ci return -EMSGSIZE; 33758c2ecf20Sopenharmony_ci} 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_cistatic void __devlink_flash_update_notify(struct devlink *devlink, 33788c2ecf20Sopenharmony_ci enum devlink_command cmd, 33798c2ecf20Sopenharmony_ci struct devlink_flash_notify *params) 33808c2ecf20Sopenharmony_ci{ 33818c2ecf20Sopenharmony_ci struct sk_buff *msg; 33828c2ecf20Sopenharmony_ci int err; 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE && 33858c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_FLASH_UPDATE_END && 33868c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS); 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 33898c2ecf20Sopenharmony_ci if (!msg) 33908c2ecf20Sopenharmony_ci return; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci err = devlink_nl_flash_update_fill(msg, devlink, cmd, params); 33938c2ecf20Sopenharmony_ci if (err) 33948c2ecf20Sopenharmony_ci goto out_free_msg; 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 33978c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 33988c2ecf20Sopenharmony_ci return; 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ciout_free_msg: 34018c2ecf20Sopenharmony_ci nlmsg_free(msg); 34028c2ecf20Sopenharmony_ci} 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_civoid devlink_flash_update_begin_notify(struct devlink *devlink) 34058c2ecf20Sopenharmony_ci{ 34068c2ecf20Sopenharmony_ci struct devlink_flash_notify params = {}; 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci __devlink_flash_update_notify(devlink, 34098c2ecf20Sopenharmony_ci DEVLINK_CMD_FLASH_UPDATE, 34108c2ecf20Sopenharmony_ci ¶ms); 34118c2ecf20Sopenharmony_ci} 34128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_civoid devlink_flash_update_end_notify(struct devlink *devlink) 34158c2ecf20Sopenharmony_ci{ 34168c2ecf20Sopenharmony_ci struct devlink_flash_notify params = {}; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci __devlink_flash_update_notify(devlink, 34198c2ecf20Sopenharmony_ci DEVLINK_CMD_FLASH_UPDATE_END, 34208c2ecf20Sopenharmony_ci ¶ms); 34218c2ecf20Sopenharmony_ci} 34228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_end_notify); 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_civoid devlink_flash_update_status_notify(struct devlink *devlink, 34258c2ecf20Sopenharmony_ci const char *status_msg, 34268c2ecf20Sopenharmony_ci const char *component, 34278c2ecf20Sopenharmony_ci unsigned long done, 34288c2ecf20Sopenharmony_ci unsigned long total) 34298c2ecf20Sopenharmony_ci{ 34308c2ecf20Sopenharmony_ci struct devlink_flash_notify params = { 34318c2ecf20Sopenharmony_ci .status_msg = status_msg, 34328c2ecf20Sopenharmony_ci .component = component, 34338c2ecf20Sopenharmony_ci .done = done, 34348c2ecf20Sopenharmony_ci .total = total, 34358c2ecf20Sopenharmony_ci }; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci __devlink_flash_update_notify(devlink, 34388c2ecf20Sopenharmony_ci DEVLINK_CMD_FLASH_UPDATE_STATUS, 34398c2ecf20Sopenharmony_ci ¶ms); 34408c2ecf20Sopenharmony_ci} 34418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_status_notify); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_civoid devlink_flash_update_timeout_notify(struct devlink *devlink, 34448c2ecf20Sopenharmony_ci const char *status_msg, 34458c2ecf20Sopenharmony_ci const char *component, 34468c2ecf20Sopenharmony_ci unsigned long timeout) 34478c2ecf20Sopenharmony_ci{ 34488c2ecf20Sopenharmony_ci struct devlink_flash_notify params = { 34498c2ecf20Sopenharmony_ci .status_msg = status_msg, 34508c2ecf20Sopenharmony_ci .component = component, 34518c2ecf20Sopenharmony_ci .timeout = timeout, 34528c2ecf20Sopenharmony_ci }; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci __devlink_flash_update_notify(devlink, 34558c2ecf20Sopenharmony_ci DEVLINK_CMD_FLASH_UPDATE_STATUS, 34568c2ecf20Sopenharmony_ci ¶ms); 34578c2ecf20Sopenharmony_ci} 34588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify); 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_flash_update(struct sk_buff *skb, 34618c2ecf20Sopenharmony_ci struct genl_info *info) 34628c2ecf20Sopenharmony_ci{ 34638c2ecf20Sopenharmony_ci struct nlattr *nla_component, *nla_overwrite_mask; 34648c2ecf20Sopenharmony_ci struct devlink_flash_update_params params = {}; 34658c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 34668c2ecf20Sopenharmony_ci u32 supported_params; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci if (!devlink->ops->flash_update) 34698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]) 34728c2ecf20Sopenharmony_ci return -EINVAL; 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci supported_params = devlink->ops->supported_flash_update_params; 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci params.file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]); 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]; 34798c2ecf20Sopenharmony_ci if (nla_component) { 34808c2ecf20Sopenharmony_ci if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT)) { 34818c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, nla_component, 34828c2ecf20Sopenharmony_ci "component update is not supported by this device"); 34838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34848c2ecf20Sopenharmony_ci } 34858c2ecf20Sopenharmony_ci params.component = nla_data(nla_component); 34868c2ecf20Sopenharmony_ci } 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK]; 34898c2ecf20Sopenharmony_ci if (nla_overwrite_mask) { 34908c2ecf20Sopenharmony_ci struct nla_bitfield32 sections; 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) { 34938c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask, 34948c2ecf20Sopenharmony_ci "overwrite settings are not supported by this device"); 34958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34968c2ecf20Sopenharmony_ci } 34978c2ecf20Sopenharmony_ci sections = nla_get_bitfield32(nla_overwrite_mask); 34988c2ecf20Sopenharmony_ci params.overwrite_mask = sections.value & sections.selector; 34998c2ecf20Sopenharmony_ci } 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci return devlink->ops->flash_update(devlink, ¶ms, info->extack); 35028c2ecf20Sopenharmony_ci} 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_cistatic const struct devlink_param devlink_param_generic[] = { 35058c2ecf20Sopenharmony_ci { 35068c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET, 35078c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME, 35088c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE, 35098c2ecf20Sopenharmony_ci }, 35108c2ecf20Sopenharmony_ci { 35118c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 35128c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME, 35138c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE, 35148c2ecf20Sopenharmony_ci }, 35158c2ecf20Sopenharmony_ci { 35168c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, 35178c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME, 35188c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE, 35198c2ecf20Sopenharmony_ci }, 35208c2ecf20Sopenharmony_ci { 35218c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT, 35228c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME, 35238c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE, 35248c2ecf20Sopenharmony_ci }, 35258c2ecf20Sopenharmony_ci { 35268c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, 35278c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME, 35288c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE, 35298c2ecf20Sopenharmony_ci }, 35308c2ecf20Sopenharmony_ci { 35318c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, 35328c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME, 35338c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE, 35348c2ecf20Sopenharmony_ci }, 35358c2ecf20Sopenharmony_ci { 35368c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, 35378c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME, 35388c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE, 35398c2ecf20Sopenharmony_ci }, 35408c2ecf20Sopenharmony_ci { 35418c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY, 35428c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME, 35438c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE, 35448c2ecf20Sopenharmony_ci }, 35458c2ecf20Sopenharmony_ci { 35468c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE, 35478c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME, 35488c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE, 35498c2ecf20Sopenharmony_ci }, 35508c2ecf20Sopenharmony_ci { 35518c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, 35528c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME, 35538c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE, 35548c2ecf20Sopenharmony_ci }, 35558c2ecf20Sopenharmony_ci { 35568c2ecf20Sopenharmony_ci .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET, 35578c2ecf20Sopenharmony_ci .name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME, 35588c2ecf20Sopenharmony_ci .type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE, 35598c2ecf20Sopenharmony_ci }, 35608c2ecf20Sopenharmony_ci}; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_cistatic int devlink_param_generic_verify(const struct devlink_param *param) 35638c2ecf20Sopenharmony_ci{ 35648c2ecf20Sopenharmony_ci /* verify it match generic parameter by id and name */ 35658c2ecf20Sopenharmony_ci if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX) 35668c2ecf20Sopenharmony_ci return -EINVAL; 35678c2ecf20Sopenharmony_ci if (strcmp(param->name, devlink_param_generic[param->id].name)) 35688c2ecf20Sopenharmony_ci return -ENOENT; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci WARN_ON(param->type != devlink_param_generic[param->id].type); 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci return 0; 35738c2ecf20Sopenharmony_ci} 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_cistatic int devlink_param_driver_verify(const struct devlink_param *param) 35768c2ecf20Sopenharmony_ci{ 35778c2ecf20Sopenharmony_ci int i; 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX) 35808c2ecf20Sopenharmony_ci return -EINVAL; 35818c2ecf20Sopenharmony_ci /* verify no such name in generic params */ 35828c2ecf20Sopenharmony_ci for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++) 35838c2ecf20Sopenharmony_ci if (!strcmp(param->name, devlink_param_generic[i].name)) 35848c2ecf20Sopenharmony_ci return -EEXIST; 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci return 0; 35878c2ecf20Sopenharmony_ci} 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_cistatic struct devlink_param_item * 35908c2ecf20Sopenharmony_cidevlink_param_find_by_name(struct list_head *param_list, 35918c2ecf20Sopenharmony_ci const char *param_name) 35928c2ecf20Sopenharmony_ci{ 35938c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci list_for_each_entry(param_item, param_list, list) 35968c2ecf20Sopenharmony_ci if (!strcmp(param_item->param->name, param_name)) 35978c2ecf20Sopenharmony_ci return param_item; 35988c2ecf20Sopenharmony_ci return NULL; 35998c2ecf20Sopenharmony_ci} 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_cistatic struct devlink_param_item * 36028c2ecf20Sopenharmony_cidevlink_param_find_by_id(struct list_head *param_list, u32 param_id) 36038c2ecf20Sopenharmony_ci{ 36048c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci list_for_each_entry(param_item, param_list, list) 36078c2ecf20Sopenharmony_ci if (param_item->param->id == param_id) 36088c2ecf20Sopenharmony_ci return param_item; 36098c2ecf20Sopenharmony_ci return NULL; 36108c2ecf20Sopenharmony_ci} 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_cistatic bool 36138c2ecf20Sopenharmony_cidevlink_param_cmode_is_supported(const struct devlink_param *param, 36148c2ecf20Sopenharmony_ci enum devlink_param_cmode cmode) 36158c2ecf20Sopenharmony_ci{ 36168c2ecf20Sopenharmony_ci return test_bit(cmode, ¶m->supported_cmodes); 36178c2ecf20Sopenharmony_ci} 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_cistatic int devlink_param_get(struct devlink *devlink, 36208c2ecf20Sopenharmony_ci const struct devlink_param *param, 36218c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 36228c2ecf20Sopenharmony_ci{ 36238c2ecf20Sopenharmony_ci if (!param->get) 36248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36258c2ecf20Sopenharmony_ci return param->get(devlink, param->id, ctx); 36268c2ecf20Sopenharmony_ci} 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_cistatic int devlink_param_set(struct devlink *devlink, 36298c2ecf20Sopenharmony_ci const struct devlink_param *param, 36308c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 36318c2ecf20Sopenharmony_ci{ 36328c2ecf20Sopenharmony_ci if (!param->set) 36338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36348c2ecf20Sopenharmony_ci return param->set(devlink, param->id, ctx); 36358c2ecf20Sopenharmony_ci} 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_cistatic int 36388c2ecf20Sopenharmony_cidevlink_param_type_to_nla_type(enum devlink_param_type param_type) 36398c2ecf20Sopenharmony_ci{ 36408c2ecf20Sopenharmony_ci switch (param_type) { 36418c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U8: 36428c2ecf20Sopenharmony_ci return NLA_U8; 36438c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U16: 36448c2ecf20Sopenharmony_ci return NLA_U16; 36458c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U32: 36468c2ecf20Sopenharmony_ci return NLA_U32; 36478c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_STRING: 36488c2ecf20Sopenharmony_ci return NLA_STRING; 36498c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_BOOL: 36508c2ecf20Sopenharmony_ci return NLA_FLAG; 36518c2ecf20Sopenharmony_ci default: 36528c2ecf20Sopenharmony_ci return -EINVAL; 36538c2ecf20Sopenharmony_ci } 36548c2ecf20Sopenharmony_ci} 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_cistatic int 36578c2ecf20Sopenharmony_cidevlink_nl_param_value_fill_one(struct sk_buff *msg, 36588c2ecf20Sopenharmony_ci enum devlink_param_type type, 36598c2ecf20Sopenharmony_ci enum devlink_param_cmode cmode, 36608c2ecf20Sopenharmony_ci union devlink_param_value val) 36618c2ecf20Sopenharmony_ci{ 36628c2ecf20Sopenharmony_ci struct nlattr *param_value_attr; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci param_value_attr = nla_nest_start_noflag(msg, 36658c2ecf20Sopenharmony_ci DEVLINK_ATTR_PARAM_VALUE); 36668c2ecf20Sopenharmony_ci if (!param_value_attr) 36678c2ecf20Sopenharmony_ci goto nla_put_failure; 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode)) 36708c2ecf20Sopenharmony_ci goto value_nest_cancel; 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_ci switch (type) { 36738c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U8: 36748c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8)) 36758c2ecf20Sopenharmony_ci goto value_nest_cancel; 36768c2ecf20Sopenharmony_ci break; 36778c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U16: 36788c2ecf20Sopenharmony_ci if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16)) 36798c2ecf20Sopenharmony_ci goto value_nest_cancel; 36808c2ecf20Sopenharmony_ci break; 36818c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U32: 36828c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32)) 36838c2ecf20Sopenharmony_ci goto value_nest_cancel; 36848c2ecf20Sopenharmony_ci break; 36858c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_STRING: 36868c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, 36878c2ecf20Sopenharmony_ci val.vstr)) 36888c2ecf20Sopenharmony_ci goto value_nest_cancel; 36898c2ecf20Sopenharmony_ci break; 36908c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_BOOL: 36918c2ecf20Sopenharmony_ci if (val.vbool && 36928c2ecf20Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA)) 36938c2ecf20Sopenharmony_ci goto value_nest_cancel; 36948c2ecf20Sopenharmony_ci break; 36958c2ecf20Sopenharmony_ci } 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci nla_nest_end(msg, param_value_attr); 36988c2ecf20Sopenharmony_ci return 0; 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_civalue_nest_cancel: 37018c2ecf20Sopenharmony_ci nla_nest_cancel(msg, param_value_attr); 37028c2ecf20Sopenharmony_cinla_put_failure: 37038c2ecf20Sopenharmony_ci return -EMSGSIZE; 37048c2ecf20Sopenharmony_ci} 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_cistatic int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, 37078c2ecf20Sopenharmony_ci unsigned int port_index, 37088c2ecf20Sopenharmony_ci struct devlink_param_item *param_item, 37098c2ecf20Sopenharmony_ci enum devlink_command cmd, 37108c2ecf20Sopenharmony_ci u32 portid, u32 seq, int flags) 37118c2ecf20Sopenharmony_ci{ 37128c2ecf20Sopenharmony_ci union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1]; 37138c2ecf20Sopenharmony_ci bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {}; 37148c2ecf20Sopenharmony_ci const struct devlink_param *param = param_item->param; 37158c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx ctx; 37168c2ecf20Sopenharmony_ci struct nlattr *param_values_list; 37178c2ecf20Sopenharmony_ci struct nlattr *param_attr; 37188c2ecf20Sopenharmony_ci int nla_type; 37198c2ecf20Sopenharmony_ci void *hdr; 37208c2ecf20Sopenharmony_ci int err; 37218c2ecf20Sopenharmony_ci int i; 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci /* Get value from driver part to driverinit configuration mode */ 37248c2ecf20Sopenharmony_ci for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) { 37258c2ecf20Sopenharmony_ci if (!devlink_param_cmode_is_supported(param, i)) 37268c2ecf20Sopenharmony_ci continue; 37278c2ecf20Sopenharmony_ci if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) { 37288c2ecf20Sopenharmony_ci if (!param_item->driverinit_value_valid) 37298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 37308c2ecf20Sopenharmony_ci param_value[i] = param_item->driverinit_value; 37318c2ecf20Sopenharmony_ci } else { 37328c2ecf20Sopenharmony_ci if (!param_item->published) 37338c2ecf20Sopenharmony_ci continue; 37348c2ecf20Sopenharmony_ci ctx.cmode = i; 37358c2ecf20Sopenharmony_ci err = devlink_param_get(devlink, param, &ctx); 37368c2ecf20Sopenharmony_ci if (err) 37378c2ecf20Sopenharmony_ci return err; 37388c2ecf20Sopenharmony_ci param_value[i] = ctx.val; 37398c2ecf20Sopenharmony_ci } 37408c2ecf20Sopenharmony_ci param_value_set[i] = true; 37418c2ecf20Sopenharmony_ci } 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 37448c2ecf20Sopenharmony_ci if (!hdr) 37458c2ecf20Sopenharmony_ci return -EMSGSIZE; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 37488c2ecf20Sopenharmony_ci goto genlmsg_cancel; 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ci if (cmd == DEVLINK_CMD_PORT_PARAM_GET || 37518c2ecf20Sopenharmony_ci cmd == DEVLINK_CMD_PORT_PARAM_NEW || 37528c2ecf20Sopenharmony_ci cmd == DEVLINK_CMD_PORT_PARAM_DEL) 37538c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index)) 37548c2ecf20Sopenharmony_ci goto genlmsg_cancel; 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM); 37578c2ecf20Sopenharmony_ci if (!param_attr) 37588c2ecf20Sopenharmony_ci goto genlmsg_cancel; 37598c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name)) 37608c2ecf20Sopenharmony_ci goto param_nest_cancel; 37618c2ecf20Sopenharmony_ci if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC)) 37628c2ecf20Sopenharmony_ci goto param_nest_cancel; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci nla_type = devlink_param_type_to_nla_type(param->type); 37658c2ecf20Sopenharmony_ci if (nla_type < 0) 37668c2ecf20Sopenharmony_ci goto param_nest_cancel; 37678c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type)) 37688c2ecf20Sopenharmony_ci goto param_nest_cancel; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci param_values_list = nla_nest_start_noflag(msg, 37718c2ecf20Sopenharmony_ci DEVLINK_ATTR_PARAM_VALUES_LIST); 37728c2ecf20Sopenharmony_ci if (!param_values_list) 37738c2ecf20Sopenharmony_ci goto param_nest_cancel; 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) { 37768c2ecf20Sopenharmony_ci if (!param_value_set[i]) 37778c2ecf20Sopenharmony_ci continue; 37788c2ecf20Sopenharmony_ci err = devlink_nl_param_value_fill_one(msg, param->type, 37798c2ecf20Sopenharmony_ci i, param_value[i]); 37808c2ecf20Sopenharmony_ci if (err) 37818c2ecf20Sopenharmony_ci goto values_list_nest_cancel; 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci nla_nest_end(msg, param_values_list); 37858c2ecf20Sopenharmony_ci nla_nest_end(msg, param_attr); 37868c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 37878c2ecf20Sopenharmony_ci return 0; 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_civalues_list_nest_cancel: 37908c2ecf20Sopenharmony_ci nla_nest_end(msg, param_values_list); 37918c2ecf20Sopenharmony_ciparam_nest_cancel: 37928c2ecf20Sopenharmony_ci nla_nest_cancel(msg, param_attr); 37938c2ecf20Sopenharmony_cigenlmsg_cancel: 37948c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 37958c2ecf20Sopenharmony_ci return -EMSGSIZE; 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_cistatic void devlink_param_notify(struct devlink *devlink, 37998c2ecf20Sopenharmony_ci unsigned int port_index, 38008c2ecf20Sopenharmony_ci struct devlink_param_item *param_item, 38018c2ecf20Sopenharmony_ci enum devlink_command cmd) 38028c2ecf20Sopenharmony_ci{ 38038c2ecf20Sopenharmony_ci struct sk_buff *msg; 38048c2ecf20Sopenharmony_ci int err; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL && 38078c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_PORT_PARAM_NEW && 38088c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_PORT_PARAM_DEL); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 38118c2ecf20Sopenharmony_ci if (!msg) 38128c2ecf20Sopenharmony_ci return; 38138c2ecf20Sopenharmony_ci err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd, 38148c2ecf20Sopenharmony_ci 0, 0, 0); 38158c2ecf20Sopenharmony_ci if (err) { 38168c2ecf20Sopenharmony_ci nlmsg_free(msg); 38178c2ecf20Sopenharmony_ci return; 38188c2ecf20Sopenharmony_ci } 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 38218c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 38228c2ecf20Sopenharmony_ci} 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg, 38258c2ecf20Sopenharmony_ci struct netlink_callback *cb) 38268c2ecf20Sopenharmony_ci{ 38278c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 38288c2ecf20Sopenharmony_ci struct devlink *devlink; 38298c2ecf20Sopenharmony_ci int start = cb->args[0]; 38308c2ecf20Sopenharmony_ci int idx = 0; 38318c2ecf20Sopenharmony_ci int err = 0; 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 38348c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 38358c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 38368c2ecf20Sopenharmony_ci continue; 38378c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 38388c2ecf20Sopenharmony_ci list_for_each_entry(param_item, &devlink->param_list, list) { 38398c2ecf20Sopenharmony_ci if (idx < start) { 38408c2ecf20Sopenharmony_ci idx++; 38418c2ecf20Sopenharmony_ci continue; 38428c2ecf20Sopenharmony_ci } 38438c2ecf20Sopenharmony_ci err = devlink_nl_param_fill(msg, devlink, 0, param_item, 38448c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_GET, 38458c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 38468c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 38478c2ecf20Sopenharmony_ci NLM_F_MULTI); 38488c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 38498c2ecf20Sopenharmony_ci err = 0; 38508c2ecf20Sopenharmony_ci } else if (err) { 38518c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 38528c2ecf20Sopenharmony_ci goto out; 38538c2ecf20Sopenharmony_ci } 38548c2ecf20Sopenharmony_ci idx++; 38558c2ecf20Sopenharmony_ci } 38568c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ciout: 38598c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 38628c2ecf20Sopenharmony_ci return err; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci cb->args[0] = idx; 38658c2ecf20Sopenharmony_ci return msg->len; 38668c2ecf20Sopenharmony_ci} 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_cistatic int 38698c2ecf20Sopenharmony_cidevlink_param_type_get_from_info(struct genl_info *info, 38708c2ecf20Sopenharmony_ci enum devlink_param_type *param_type) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE]) 38738c2ecf20Sopenharmony_ci return -EINVAL; 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_ci switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) { 38768c2ecf20Sopenharmony_ci case NLA_U8: 38778c2ecf20Sopenharmony_ci *param_type = DEVLINK_PARAM_TYPE_U8; 38788c2ecf20Sopenharmony_ci break; 38798c2ecf20Sopenharmony_ci case NLA_U16: 38808c2ecf20Sopenharmony_ci *param_type = DEVLINK_PARAM_TYPE_U16; 38818c2ecf20Sopenharmony_ci break; 38828c2ecf20Sopenharmony_ci case NLA_U32: 38838c2ecf20Sopenharmony_ci *param_type = DEVLINK_PARAM_TYPE_U32; 38848c2ecf20Sopenharmony_ci break; 38858c2ecf20Sopenharmony_ci case NLA_STRING: 38868c2ecf20Sopenharmony_ci *param_type = DEVLINK_PARAM_TYPE_STRING; 38878c2ecf20Sopenharmony_ci break; 38888c2ecf20Sopenharmony_ci case NLA_FLAG: 38898c2ecf20Sopenharmony_ci *param_type = DEVLINK_PARAM_TYPE_BOOL; 38908c2ecf20Sopenharmony_ci break; 38918c2ecf20Sopenharmony_ci default: 38928c2ecf20Sopenharmony_ci return -EINVAL; 38938c2ecf20Sopenharmony_ci } 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci return 0; 38968c2ecf20Sopenharmony_ci} 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_cistatic int 38998c2ecf20Sopenharmony_cidevlink_param_value_get_from_info(const struct devlink_param *param, 39008c2ecf20Sopenharmony_ci struct genl_info *info, 39018c2ecf20Sopenharmony_ci union devlink_param_value *value) 39028c2ecf20Sopenharmony_ci{ 39038c2ecf20Sopenharmony_ci struct nlattr *param_data; 39048c2ecf20Sopenharmony_ci int len; 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_ci if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data) 39098c2ecf20Sopenharmony_ci return -EINVAL; 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci switch (param->type) { 39128c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U8: 39138c2ecf20Sopenharmony_ci if (nla_len(param_data) != sizeof(u8)) 39148c2ecf20Sopenharmony_ci return -EINVAL; 39158c2ecf20Sopenharmony_ci value->vu8 = nla_get_u8(param_data); 39168c2ecf20Sopenharmony_ci break; 39178c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U16: 39188c2ecf20Sopenharmony_ci if (nla_len(param_data) != sizeof(u16)) 39198c2ecf20Sopenharmony_ci return -EINVAL; 39208c2ecf20Sopenharmony_ci value->vu16 = nla_get_u16(param_data); 39218c2ecf20Sopenharmony_ci break; 39228c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_U32: 39238c2ecf20Sopenharmony_ci if (nla_len(param_data) != sizeof(u32)) 39248c2ecf20Sopenharmony_ci return -EINVAL; 39258c2ecf20Sopenharmony_ci value->vu32 = nla_get_u32(param_data); 39268c2ecf20Sopenharmony_ci break; 39278c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_STRING: 39288c2ecf20Sopenharmony_ci len = strnlen(nla_data(param_data), nla_len(param_data)); 39298c2ecf20Sopenharmony_ci if (len == nla_len(param_data) || 39308c2ecf20Sopenharmony_ci len >= __DEVLINK_PARAM_MAX_STRING_VALUE) 39318c2ecf20Sopenharmony_ci return -EINVAL; 39328c2ecf20Sopenharmony_ci strcpy(value->vstr, nla_data(param_data)); 39338c2ecf20Sopenharmony_ci break; 39348c2ecf20Sopenharmony_ci case DEVLINK_PARAM_TYPE_BOOL: 39358c2ecf20Sopenharmony_ci if (param_data && nla_len(param_data)) 39368c2ecf20Sopenharmony_ci return -EINVAL; 39378c2ecf20Sopenharmony_ci value->vbool = nla_get_flag(param_data); 39388c2ecf20Sopenharmony_ci break; 39398c2ecf20Sopenharmony_ci } 39408c2ecf20Sopenharmony_ci return 0; 39418c2ecf20Sopenharmony_ci} 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_cistatic struct devlink_param_item * 39448c2ecf20Sopenharmony_cidevlink_param_get_from_info(struct list_head *param_list, 39458c2ecf20Sopenharmony_ci struct genl_info *info) 39468c2ecf20Sopenharmony_ci{ 39478c2ecf20Sopenharmony_ci char *param_name; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_PARAM_NAME]) 39508c2ecf20Sopenharmony_ci return NULL; 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]); 39538c2ecf20Sopenharmony_ci return devlink_param_find_by_name(param_list, param_name); 39548c2ecf20Sopenharmony_ci} 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_get_doit(struct sk_buff *skb, 39578c2ecf20Sopenharmony_ci struct genl_info *info) 39588c2ecf20Sopenharmony_ci{ 39598c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 39608c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 39618c2ecf20Sopenharmony_ci struct sk_buff *msg; 39628c2ecf20Sopenharmony_ci int err; 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci param_item = devlink_param_get_from_info(&devlink->param_list, info); 39658c2ecf20Sopenharmony_ci if (!param_item) 39668c2ecf20Sopenharmony_ci return -EINVAL; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 39698c2ecf20Sopenharmony_ci if (!msg) 39708c2ecf20Sopenharmony_ci return -ENOMEM; 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_ci err = devlink_nl_param_fill(msg, devlink, 0, param_item, 39738c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_GET, 39748c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 39758c2ecf20Sopenharmony_ci if (err) { 39768c2ecf20Sopenharmony_ci nlmsg_free(msg); 39778c2ecf20Sopenharmony_ci return err; 39788c2ecf20Sopenharmony_ci } 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 39818c2ecf20Sopenharmony_ci} 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_cistatic int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, 39848c2ecf20Sopenharmony_ci unsigned int port_index, 39858c2ecf20Sopenharmony_ci struct list_head *param_list, 39868c2ecf20Sopenharmony_ci struct genl_info *info, 39878c2ecf20Sopenharmony_ci enum devlink_command cmd) 39888c2ecf20Sopenharmony_ci{ 39898c2ecf20Sopenharmony_ci enum devlink_param_type param_type; 39908c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx ctx; 39918c2ecf20Sopenharmony_ci enum devlink_param_cmode cmode; 39928c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 39938c2ecf20Sopenharmony_ci const struct devlink_param *param; 39948c2ecf20Sopenharmony_ci union devlink_param_value value; 39958c2ecf20Sopenharmony_ci int err = 0; 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci param_item = devlink_param_get_from_info(param_list, info); 39988c2ecf20Sopenharmony_ci if (!param_item) 39998c2ecf20Sopenharmony_ci return -EINVAL; 40008c2ecf20Sopenharmony_ci param = param_item->param; 40018c2ecf20Sopenharmony_ci err = devlink_param_type_get_from_info(info, ¶m_type); 40028c2ecf20Sopenharmony_ci if (err) 40038c2ecf20Sopenharmony_ci return err; 40048c2ecf20Sopenharmony_ci if (param_type != param->type) 40058c2ecf20Sopenharmony_ci return -EINVAL; 40068c2ecf20Sopenharmony_ci err = devlink_param_value_get_from_info(param, info, &value); 40078c2ecf20Sopenharmony_ci if (err) 40088c2ecf20Sopenharmony_ci return err; 40098c2ecf20Sopenharmony_ci if (param->validate) { 40108c2ecf20Sopenharmony_ci err = param->validate(devlink, param->id, value, info->extack); 40118c2ecf20Sopenharmony_ci if (err) 40128c2ecf20Sopenharmony_ci return err; 40138c2ecf20Sopenharmony_ci } 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]) 40168c2ecf20Sopenharmony_ci return -EINVAL; 40178c2ecf20Sopenharmony_ci cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]); 40188c2ecf20Sopenharmony_ci if (!devlink_param_cmode_is_supported(param, cmode)) 40198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) { 40228c2ecf20Sopenharmony_ci if (param->type == DEVLINK_PARAM_TYPE_STRING) 40238c2ecf20Sopenharmony_ci strcpy(param_item->driverinit_value.vstr, value.vstr); 40248c2ecf20Sopenharmony_ci else 40258c2ecf20Sopenharmony_ci param_item->driverinit_value = value; 40268c2ecf20Sopenharmony_ci param_item->driverinit_value_valid = true; 40278c2ecf20Sopenharmony_ci } else { 40288c2ecf20Sopenharmony_ci if (!param->set) 40298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 40308c2ecf20Sopenharmony_ci ctx.val = value; 40318c2ecf20Sopenharmony_ci ctx.cmode = cmode; 40328c2ecf20Sopenharmony_ci err = devlink_param_set(devlink, param, &ctx); 40338c2ecf20Sopenharmony_ci if (err) 40348c2ecf20Sopenharmony_ci return err; 40358c2ecf20Sopenharmony_ci } 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci devlink_param_notify(devlink, port_index, param_item, cmd); 40388c2ecf20Sopenharmony_ci return 0; 40398c2ecf20Sopenharmony_ci} 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_set_doit(struct sk_buff *skb, 40428c2ecf20Sopenharmony_ci struct genl_info *info) 40438c2ecf20Sopenharmony_ci{ 40448c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list, 40478c2ecf20Sopenharmony_ci info, DEVLINK_CMD_PARAM_NEW); 40488c2ecf20Sopenharmony_ci} 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_cistatic int devlink_param_register_one(struct devlink *devlink, 40518c2ecf20Sopenharmony_ci unsigned int port_index, 40528c2ecf20Sopenharmony_ci struct list_head *param_list, 40538c2ecf20Sopenharmony_ci const struct devlink_param *param, 40548c2ecf20Sopenharmony_ci enum devlink_command cmd) 40558c2ecf20Sopenharmony_ci{ 40568c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci if (devlink_param_find_by_name(param_list, param->name)) 40598c2ecf20Sopenharmony_ci return -EEXIST; 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT)) 40628c2ecf20Sopenharmony_ci WARN_ON(param->get || param->set); 40638c2ecf20Sopenharmony_ci else 40648c2ecf20Sopenharmony_ci WARN_ON(!param->get || !param->set); 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci param_item = kzalloc(sizeof(*param_item), GFP_KERNEL); 40678c2ecf20Sopenharmony_ci if (!param_item) 40688c2ecf20Sopenharmony_ci return -ENOMEM; 40698c2ecf20Sopenharmony_ci param_item->param = param; 40708c2ecf20Sopenharmony_ci 40718c2ecf20Sopenharmony_ci list_add_tail(¶m_item->list, param_list); 40728c2ecf20Sopenharmony_ci devlink_param_notify(devlink, port_index, param_item, cmd); 40738c2ecf20Sopenharmony_ci return 0; 40748c2ecf20Sopenharmony_ci} 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_cistatic void devlink_param_unregister_one(struct devlink *devlink, 40778c2ecf20Sopenharmony_ci unsigned int port_index, 40788c2ecf20Sopenharmony_ci struct list_head *param_list, 40798c2ecf20Sopenharmony_ci const struct devlink_param *param, 40808c2ecf20Sopenharmony_ci enum devlink_command cmd) 40818c2ecf20Sopenharmony_ci{ 40828c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci param_item = devlink_param_find_by_name(param_list, param->name); 40858c2ecf20Sopenharmony_ci WARN_ON(!param_item); 40868c2ecf20Sopenharmony_ci devlink_param_notify(devlink, port_index, param_item, cmd); 40878c2ecf20Sopenharmony_ci list_del(¶m_item->list); 40888c2ecf20Sopenharmony_ci kfree(param_item); 40898c2ecf20Sopenharmony_ci} 40908c2ecf20Sopenharmony_ci 40918c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg, 40928c2ecf20Sopenharmony_ci struct netlink_callback *cb) 40938c2ecf20Sopenharmony_ci{ 40948c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 40958c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 40968c2ecf20Sopenharmony_ci struct devlink *devlink; 40978c2ecf20Sopenharmony_ci int start = cb->args[0]; 40988c2ecf20Sopenharmony_ci int idx = 0; 40998c2ecf20Sopenharmony_ci int err = 0; 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 41028c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 41038c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 41048c2ecf20Sopenharmony_ci continue; 41058c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 41068c2ecf20Sopenharmony_ci list_for_each_entry(devlink_port, &devlink->port_list, list) { 41078c2ecf20Sopenharmony_ci list_for_each_entry(param_item, 41088c2ecf20Sopenharmony_ci &devlink_port->param_list, list) { 41098c2ecf20Sopenharmony_ci if (idx < start) { 41108c2ecf20Sopenharmony_ci idx++; 41118c2ecf20Sopenharmony_ci continue; 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci err = devlink_nl_param_fill(msg, 41148c2ecf20Sopenharmony_ci devlink_port->devlink, 41158c2ecf20Sopenharmony_ci devlink_port->index, param_item, 41168c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_GET, 41178c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 41188c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 41198c2ecf20Sopenharmony_ci NLM_F_MULTI); 41208c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) { 41218c2ecf20Sopenharmony_ci err = 0; 41228c2ecf20Sopenharmony_ci } else if (err) { 41238c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 41248c2ecf20Sopenharmony_ci goto out; 41258c2ecf20Sopenharmony_ci } 41268c2ecf20Sopenharmony_ci idx++; 41278c2ecf20Sopenharmony_ci } 41288c2ecf20Sopenharmony_ci } 41298c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 41308c2ecf20Sopenharmony_ci } 41318c2ecf20Sopenharmony_ciout: 41328c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 41358c2ecf20Sopenharmony_ci return err; 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci cb->args[0] = idx; 41388c2ecf20Sopenharmony_ci return msg->len; 41398c2ecf20Sopenharmony_ci} 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb, 41428c2ecf20Sopenharmony_ci struct genl_info *info) 41438c2ecf20Sopenharmony_ci{ 41448c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 41458c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 41468c2ecf20Sopenharmony_ci struct sk_buff *msg; 41478c2ecf20Sopenharmony_ci int err; 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci param_item = devlink_param_get_from_info(&devlink_port->param_list, 41508c2ecf20Sopenharmony_ci info); 41518c2ecf20Sopenharmony_ci if (!param_item) 41528c2ecf20Sopenharmony_ci return -EINVAL; 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 41558c2ecf20Sopenharmony_ci if (!msg) 41568c2ecf20Sopenharmony_ci return -ENOMEM; 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci err = devlink_nl_param_fill(msg, devlink_port->devlink, 41598c2ecf20Sopenharmony_ci devlink_port->index, param_item, 41608c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_GET, 41618c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 41628c2ecf20Sopenharmony_ci if (err) { 41638c2ecf20Sopenharmony_ci nlmsg_free(msg); 41648c2ecf20Sopenharmony_ci return err; 41658c2ecf20Sopenharmony_ci } 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 41688c2ecf20Sopenharmony_ci} 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb, 41718c2ecf20Sopenharmony_ci struct genl_info *info) 41728c2ecf20Sopenharmony_ci{ 41738c2ecf20Sopenharmony_ci struct devlink_port *devlink_port = info->user_ptr[1]; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci return __devlink_nl_cmd_param_set_doit(devlink_port->devlink, 41768c2ecf20Sopenharmony_ci devlink_port->index, 41778c2ecf20Sopenharmony_ci &devlink_port->param_list, info, 41788c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_NEW); 41798c2ecf20Sopenharmony_ci} 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_cistatic int devlink_nl_region_snapshot_id_put(struct sk_buff *msg, 41828c2ecf20Sopenharmony_ci struct devlink *devlink, 41838c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot) 41848c2ecf20Sopenharmony_ci{ 41858c2ecf20Sopenharmony_ci struct nlattr *snap_attr; 41868c2ecf20Sopenharmony_ci int err; 41878c2ecf20Sopenharmony_ci 41888c2ecf20Sopenharmony_ci snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT); 41898c2ecf20Sopenharmony_ci if (!snap_attr) 41908c2ecf20Sopenharmony_ci return -EINVAL; 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id); 41938c2ecf20Sopenharmony_ci if (err) 41948c2ecf20Sopenharmony_ci goto nla_put_failure; 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_ci nla_nest_end(msg, snap_attr); 41978c2ecf20Sopenharmony_ci return 0; 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_cinla_put_failure: 42008c2ecf20Sopenharmony_ci nla_nest_cancel(msg, snap_attr); 42018c2ecf20Sopenharmony_ci return err; 42028c2ecf20Sopenharmony_ci} 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_cistatic int devlink_nl_region_snapshots_id_put(struct sk_buff *msg, 42058c2ecf20Sopenharmony_ci struct devlink *devlink, 42068c2ecf20Sopenharmony_ci struct devlink_region *region) 42078c2ecf20Sopenharmony_ci{ 42088c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 42098c2ecf20Sopenharmony_ci struct nlattr *snapshots_attr; 42108c2ecf20Sopenharmony_ci int err; 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci snapshots_attr = nla_nest_start_noflag(msg, 42138c2ecf20Sopenharmony_ci DEVLINK_ATTR_REGION_SNAPSHOTS); 42148c2ecf20Sopenharmony_ci if (!snapshots_attr) 42158c2ecf20Sopenharmony_ci return -EINVAL; 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci list_for_each_entry(snapshot, ®ion->snapshot_list, list) { 42188c2ecf20Sopenharmony_ci err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot); 42198c2ecf20Sopenharmony_ci if (err) 42208c2ecf20Sopenharmony_ci goto nla_put_failure; 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci nla_nest_end(msg, snapshots_attr); 42248c2ecf20Sopenharmony_ci return 0; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_cinla_put_failure: 42278c2ecf20Sopenharmony_ci nla_nest_cancel(msg, snapshots_attr); 42288c2ecf20Sopenharmony_ci return err; 42298c2ecf20Sopenharmony_ci} 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_cistatic int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink, 42328c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 42338c2ecf20Sopenharmony_ci u32 seq, int flags, 42348c2ecf20Sopenharmony_ci struct devlink_region *region) 42358c2ecf20Sopenharmony_ci{ 42368c2ecf20Sopenharmony_ci void *hdr; 42378c2ecf20Sopenharmony_ci int err; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 42408c2ecf20Sopenharmony_ci if (!hdr) 42418c2ecf20Sopenharmony_ci return -EMSGSIZE; 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci err = devlink_nl_put_handle(msg, devlink); 42448c2ecf20Sopenharmony_ci if (err) 42458c2ecf20Sopenharmony_ci goto nla_put_failure; 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci if (region->port) { 42488c2ecf20Sopenharmony_ci err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, 42498c2ecf20Sopenharmony_ci region->port->index); 42508c2ecf20Sopenharmony_ci if (err) 42518c2ecf20Sopenharmony_ci goto nla_put_failure; 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name); 42558c2ecf20Sopenharmony_ci if (err) 42568c2ecf20Sopenharmony_ci goto nla_put_failure; 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE, 42598c2ecf20Sopenharmony_ci region->size, 42608c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD); 42618c2ecf20Sopenharmony_ci if (err) 42628c2ecf20Sopenharmony_ci goto nla_put_failure; 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci err = devlink_nl_region_snapshots_id_put(msg, devlink, region); 42658c2ecf20Sopenharmony_ci if (err) 42668c2ecf20Sopenharmony_ci goto nla_put_failure; 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 42698c2ecf20Sopenharmony_ci return 0; 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_cinla_put_failure: 42728c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 42738c2ecf20Sopenharmony_ci return err; 42748c2ecf20Sopenharmony_ci} 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_cistatic struct sk_buff * 42778c2ecf20Sopenharmony_cidevlink_nl_region_notify_build(struct devlink_region *region, 42788c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot, 42798c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq) 42808c2ecf20Sopenharmony_ci{ 42818c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 42828c2ecf20Sopenharmony_ci struct sk_buff *msg; 42838c2ecf20Sopenharmony_ci void *hdr; 42848c2ecf20Sopenharmony_ci int err; 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 42888c2ecf20Sopenharmony_ci if (!msg) 42898c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 42908c2ecf20Sopenharmony_ci 42918c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd); 42928c2ecf20Sopenharmony_ci if (!hdr) { 42938c2ecf20Sopenharmony_ci err = -EMSGSIZE; 42948c2ecf20Sopenharmony_ci goto out_free_msg; 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci err = devlink_nl_put_handle(msg, devlink); 42988c2ecf20Sopenharmony_ci if (err) 42998c2ecf20Sopenharmony_ci goto out_cancel_msg; 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci if (region->port) { 43028c2ecf20Sopenharmony_ci err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, 43038c2ecf20Sopenharmony_ci region->port->index); 43048c2ecf20Sopenharmony_ci if (err) 43058c2ecf20Sopenharmony_ci goto out_cancel_msg; 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, 43098c2ecf20Sopenharmony_ci region->ops->name); 43108c2ecf20Sopenharmony_ci if (err) 43118c2ecf20Sopenharmony_ci goto out_cancel_msg; 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci if (snapshot) { 43148c2ecf20Sopenharmony_ci err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, 43158c2ecf20Sopenharmony_ci snapshot->id); 43168c2ecf20Sopenharmony_ci if (err) 43178c2ecf20Sopenharmony_ci goto out_cancel_msg; 43188c2ecf20Sopenharmony_ci } else { 43198c2ecf20Sopenharmony_ci err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE, 43208c2ecf20Sopenharmony_ci region->size, DEVLINK_ATTR_PAD); 43218c2ecf20Sopenharmony_ci if (err) 43228c2ecf20Sopenharmony_ci goto out_cancel_msg; 43238c2ecf20Sopenharmony_ci } 43248c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_ci return msg; 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_ciout_cancel_msg: 43298c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 43308c2ecf20Sopenharmony_ciout_free_msg: 43318c2ecf20Sopenharmony_ci nlmsg_free(msg); 43328c2ecf20Sopenharmony_ci return ERR_PTR(err); 43338c2ecf20Sopenharmony_ci} 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_cistatic void devlink_nl_region_notify(struct devlink_region *region, 43368c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot, 43378c2ecf20Sopenharmony_ci enum devlink_command cmd) 43388c2ecf20Sopenharmony_ci{ 43398c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 43408c2ecf20Sopenharmony_ci struct sk_buff *msg; 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL); 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0); 43458c2ecf20Sopenharmony_ci if (IS_ERR(msg)) 43468c2ecf20Sopenharmony_ci return; 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 43498c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 43508c2ecf20Sopenharmony_ci} 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci/** 43538c2ecf20Sopenharmony_ci * __devlink_snapshot_id_increment - Increment number of snapshots using an id 43548c2ecf20Sopenharmony_ci * @devlink: devlink instance 43558c2ecf20Sopenharmony_ci * @id: the snapshot id 43568c2ecf20Sopenharmony_ci * 43578c2ecf20Sopenharmony_ci * Track when a new snapshot begins using an id. Load the count for the 43588c2ecf20Sopenharmony_ci * given id from the snapshot xarray, increment it, and store it back. 43598c2ecf20Sopenharmony_ci * 43608c2ecf20Sopenharmony_ci * Called when a new snapshot is created with the given id. 43618c2ecf20Sopenharmony_ci * 43628c2ecf20Sopenharmony_ci * The id *must* have been previously allocated by 43638c2ecf20Sopenharmony_ci * devlink_region_snapshot_id_get(). 43648c2ecf20Sopenharmony_ci * 43658c2ecf20Sopenharmony_ci * Returns 0 on success, or an error on failure. 43668c2ecf20Sopenharmony_ci */ 43678c2ecf20Sopenharmony_cistatic int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id) 43688c2ecf20Sopenharmony_ci{ 43698c2ecf20Sopenharmony_ci unsigned long count; 43708c2ecf20Sopenharmony_ci void *p; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci p = xa_load(&devlink->snapshot_ids, id); 43758c2ecf20Sopenharmony_ci if (WARN_ON(!p)) 43768c2ecf20Sopenharmony_ci return -EINVAL; 43778c2ecf20Sopenharmony_ci 43788c2ecf20Sopenharmony_ci if (WARN_ON(!xa_is_value(p))) 43798c2ecf20Sopenharmony_ci return -EINVAL; 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ci count = xa_to_value(p); 43828c2ecf20Sopenharmony_ci count++; 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count), 43858c2ecf20Sopenharmony_ci GFP_KERNEL)); 43868c2ecf20Sopenharmony_ci} 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci/** 43898c2ecf20Sopenharmony_ci * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id 43908c2ecf20Sopenharmony_ci * @devlink: devlink instance 43918c2ecf20Sopenharmony_ci * @id: the snapshot id 43928c2ecf20Sopenharmony_ci * 43938c2ecf20Sopenharmony_ci * Track when a snapshot is deleted and stops using an id. Load the count 43948c2ecf20Sopenharmony_ci * for the given id from the snapshot xarray, decrement it, and store it 43958c2ecf20Sopenharmony_ci * back. 43968c2ecf20Sopenharmony_ci * 43978c2ecf20Sopenharmony_ci * If the count reaches zero, erase this id from the xarray, freeing it 43988c2ecf20Sopenharmony_ci * up for future re-use by devlink_region_snapshot_id_get(). 43998c2ecf20Sopenharmony_ci * 44008c2ecf20Sopenharmony_ci * Called when a snapshot using the given id is deleted, and when the 44018c2ecf20Sopenharmony_ci * initial allocator of the id is finished using it. 44028c2ecf20Sopenharmony_ci */ 44038c2ecf20Sopenharmony_cistatic void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id) 44048c2ecf20Sopenharmony_ci{ 44058c2ecf20Sopenharmony_ci unsigned long count; 44068c2ecf20Sopenharmony_ci void *p; 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci p = xa_load(&devlink->snapshot_ids, id); 44118c2ecf20Sopenharmony_ci if (WARN_ON(!p)) 44128c2ecf20Sopenharmony_ci return; 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci if (WARN_ON(!xa_is_value(p))) 44158c2ecf20Sopenharmony_ci return; 44168c2ecf20Sopenharmony_ci 44178c2ecf20Sopenharmony_ci count = xa_to_value(p); 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci if (count > 1) { 44208c2ecf20Sopenharmony_ci count--; 44218c2ecf20Sopenharmony_ci xa_store(&devlink->snapshot_ids, id, xa_mk_value(count), 44228c2ecf20Sopenharmony_ci GFP_KERNEL); 44238c2ecf20Sopenharmony_ci } else { 44248c2ecf20Sopenharmony_ci /* If this was the last user, we can erase this id */ 44258c2ecf20Sopenharmony_ci xa_erase(&devlink->snapshot_ids, id); 44268c2ecf20Sopenharmony_ci } 44278c2ecf20Sopenharmony_ci} 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci/** 44308c2ecf20Sopenharmony_ci * __devlink_snapshot_id_insert - Insert a specific snapshot ID 44318c2ecf20Sopenharmony_ci * @devlink: devlink instance 44328c2ecf20Sopenharmony_ci * @id: the snapshot id 44338c2ecf20Sopenharmony_ci * 44348c2ecf20Sopenharmony_ci * Mark the given snapshot id as used by inserting a zero value into the 44358c2ecf20Sopenharmony_ci * snapshot xarray. 44368c2ecf20Sopenharmony_ci * 44378c2ecf20Sopenharmony_ci * This must be called while holding the devlink instance lock. Unlike 44388c2ecf20Sopenharmony_ci * devlink_snapshot_id_get, the initial reference count is zero, not one. 44398c2ecf20Sopenharmony_ci * It is expected that the id will immediately be used before 44408c2ecf20Sopenharmony_ci * releasing the devlink instance lock. 44418c2ecf20Sopenharmony_ci * 44428c2ecf20Sopenharmony_ci * Returns zero on success, or an error code if the snapshot id could not 44438c2ecf20Sopenharmony_ci * be inserted. 44448c2ecf20Sopenharmony_ci */ 44458c2ecf20Sopenharmony_cistatic int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id) 44468c2ecf20Sopenharmony_ci{ 44478c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci if (xa_load(&devlink->snapshot_ids, id)) 44508c2ecf20Sopenharmony_ci return -EEXIST; 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0), 44538c2ecf20Sopenharmony_ci GFP_KERNEL)); 44548c2ecf20Sopenharmony_ci} 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci/** 44578c2ecf20Sopenharmony_ci * __devlink_region_snapshot_id_get - get snapshot ID 44588c2ecf20Sopenharmony_ci * @devlink: devlink instance 44598c2ecf20Sopenharmony_ci * @id: storage to return snapshot id 44608c2ecf20Sopenharmony_ci * 44618c2ecf20Sopenharmony_ci * Allocates a new snapshot id. Returns zero on success, or a negative 44628c2ecf20Sopenharmony_ci * error on failure. Must be called while holding the devlink instance 44638c2ecf20Sopenharmony_ci * lock. 44648c2ecf20Sopenharmony_ci * 44658c2ecf20Sopenharmony_ci * Snapshot IDs are tracked using an xarray which stores the number of 44668c2ecf20Sopenharmony_ci * users of the snapshot id. 44678c2ecf20Sopenharmony_ci * 44688c2ecf20Sopenharmony_ci * Note that the caller of this function counts as a 'user', in order to 44698c2ecf20Sopenharmony_ci * avoid race conditions. The caller must release its hold on the 44708c2ecf20Sopenharmony_ci * snapshot by using devlink_region_snapshot_id_put. 44718c2ecf20Sopenharmony_ci */ 44728c2ecf20Sopenharmony_cistatic int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id) 44738c2ecf20Sopenharmony_ci{ 44748c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1), 44778c2ecf20Sopenharmony_ci xa_limit_32b, GFP_KERNEL); 44788c2ecf20Sopenharmony_ci} 44798c2ecf20Sopenharmony_ci 44808c2ecf20Sopenharmony_ci/** 44818c2ecf20Sopenharmony_ci * __devlink_region_snapshot_create - create a new snapshot 44828c2ecf20Sopenharmony_ci * This will add a new snapshot of a region. The snapshot 44838c2ecf20Sopenharmony_ci * will be stored on the region struct and can be accessed 44848c2ecf20Sopenharmony_ci * from devlink. This is useful for future analyses of snapshots. 44858c2ecf20Sopenharmony_ci * Multiple snapshots can be created on a region. 44868c2ecf20Sopenharmony_ci * The @snapshot_id should be obtained using the getter function. 44878c2ecf20Sopenharmony_ci * 44888c2ecf20Sopenharmony_ci * Must be called only while holding the devlink instance lock. 44898c2ecf20Sopenharmony_ci * 44908c2ecf20Sopenharmony_ci * @region: devlink region of the snapshot 44918c2ecf20Sopenharmony_ci * @data: snapshot data 44928c2ecf20Sopenharmony_ci * @snapshot_id: snapshot id to be created 44938c2ecf20Sopenharmony_ci */ 44948c2ecf20Sopenharmony_cistatic int 44958c2ecf20Sopenharmony_ci__devlink_region_snapshot_create(struct devlink_region *region, 44968c2ecf20Sopenharmony_ci u8 *data, u32 snapshot_id) 44978c2ecf20Sopenharmony_ci{ 44988c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 44998c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 45008c2ecf20Sopenharmony_ci int err; 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 45038c2ecf20Sopenharmony_ci 45048c2ecf20Sopenharmony_ci /* check if region can hold one more snapshot */ 45058c2ecf20Sopenharmony_ci if (region->cur_snapshots == region->max_snapshots) 45068c2ecf20Sopenharmony_ci return -ENOSPC; 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci if (devlink_region_snapshot_get_by_id(region, snapshot_id)) 45098c2ecf20Sopenharmony_ci return -EEXIST; 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL); 45128c2ecf20Sopenharmony_ci if (!snapshot) 45138c2ecf20Sopenharmony_ci return -ENOMEM; 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci err = __devlink_snapshot_id_increment(devlink, snapshot_id); 45168c2ecf20Sopenharmony_ci if (err) 45178c2ecf20Sopenharmony_ci goto err_snapshot_id_increment; 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci snapshot->id = snapshot_id; 45208c2ecf20Sopenharmony_ci snapshot->region = region; 45218c2ecf20Sopenharmony_ci snapshot->data = data; 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci list_add_tail(&snapshot->list, ®ion->snapshot_list); 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci region->cur_snapshots++; 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW); 45288c2ecf20Sopenharmony_ci return 0; 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_cierr_snapshot_id_increment: 45318c2ecf20Sopenharmony_ci kfree(snapshot); 45328c2ecf20Sopenharmony_ci return err; 45338c2ecf20Sopenharmony_ci} 45348c2ecf20Sopenharmony_ci 45358c2ecf20Sopenharmony_cistatic void devlink_region_snapshot_del(struct devlink_region *region, 45368c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot) 45378c2ecf20Sopenharmony_ci{ 45388c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 45398c2ecf20Sopenharmony_ci 45408c2ecf20Sopenharmony_ci lockdep_assert_held(&devlink->lock); 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL); 45438c2ecf20Sopenharmony_ci region->cur_snapshots--; 45448c2ecf20Sopenharmony_ci list_del(&snapshot->list); 45458c2ecf20Sopenharmony_ci region->ops->destructor(snapshot->data); 45468c2ecf20Sopenharmony_ci __devlink_snapshot_id_decrement(devlink, snapshot->id); 45478c2ecf20Sopenharmony_ci kfree(snapshot); 45488c2ecf20Sopenharmony_ci} 45498c2ecf20Sopenharmony_ci 45508c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_doit(struct sk_buff *skb, 45518c2ecf20Sopenharmony_ci struct genl_info *info) 45528c2ecf20Sopenharmony_ci{ 45538c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 45548c2ecf20Sopenharmony_ci struct devlink_port *port = NULL; 45558c2ecf20Sopenharmony_ci struct devlink_region *region; 45568c2ecf20Sopenharmony_ci const char *region_name; 45578c2ecf20Sopenharmony_ci struct sk_buff *msg; 45588c2ecf20Sopenharmony_ci unsigned int index; 45598c2ecf20Sopenharmony_ci int err; 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) 45628c2ecf20Sopenharmony_ci return -EINVAL; 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 45658c2ecf20Sopenharmony_ci index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 45668c2ecf20Sopenharmony_ci 45678c2ecf20Sopenharmony_ci port = devlink_port_get_by_index(devlink, index); 45688c2ecf20Sopenharmony_ci if (!port) 45698c2ecf20Sopenharmony_ci return -ENODEV; 45708c2ecf20Sopenharmony_ci } 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 45738c2ecf20Sopenharmony_ci if (port) 45748c2ecf20Sopenharmony_ci region = devlink_port_region_get_by_name(port, region_name); 45758c2ecf20Sopenharmony_ci else 45768c2ecf20Sopenharmony_ci region = devlink_region_get_by_name(devlink, region_name); 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci if (!region) 45798c2ecf20Sopenharmony_ci return -EINVAL; 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 45828c2ecf20Sopenharmony_ci if (!msg) 45838c2ecf20Sopenharmony_ci return -ENOMEM; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET, 45868c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0, 45878c2ecf20Sopenharmony_ci region); 45888c2ecf20Sopenharmony_ci if (err) { 45898c2ecf20Sopenharmony_ci nlmsg_free(msg); 45908c2ecf20Sopenharmony_ci return err; 45918c2ecf20Sopenharmony_ci } 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 45948c2ecf20Sopenharmony_ci} 45958c2ecf20Sopenharmony_ci 45968c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg, 45978c2ecf20Sopenharmony_ci struct netlink_callback *cb, 45988c2ecf20Sopenharmony_ci struct devlink_port *port, 45998c2ecf20Sopenharmony_ci int *idx, 46008c2ecf20Sopenharmony_ci int start) 46018c2ecf20Sopenharmony_ci{ 46028c2ecf20Sopenharmony_ci struct devlink_region *region; 46038c2ecf20Sopenharmony_ci int err = 0; 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci list_for_each_entry(region, &port->region_list, list) { 46068c2ecf20Sopenharmony_ci if (*idx < start) { 46078c2ecf20Sopenharmony_ci (*idx)++; 46088c2ecf20Sopenharmony_ci continue; 46098c2ecf20Sopenharmony_ci } 46108c2ecf20Sopenharmony_ci err = devlink_nl_region_fill(msg, port->devlink, 46118c2ecf20Sopenharmony_ci DEVLINK_CMD_REGION_GET, 46128c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 46138c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 46148c2ecf20Sopenharmony_ci NLM_F_MULTI, region); 46158c2ecf20Sopenharmony_ci if (err) 46168c2ecf20Sopenharmony_ci goto out; 46178c2ecf20Sopenharmony_ci (*idx)++; 46188c2ecf20Sopenharmony_ci } 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ciout: 46218c2ecf20Sopenharmony_ci return err; 46228c2ecf20Sopenharmony_ci} 46238c2ecf20Sopenharmony_ci 46248c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg, 46258c2ecf20Sopenharmony_ci struct netlink_callback *cb, 46268c2ecf20Sopenharmony_ci struct devlink *devlink, 46278c2ecf20Sopenharmony_ci int *idx, 46288c2ecf20Sopenharmony_ci int start) 46298c2ecf20Sopenharmony_ci{ 46308c2ecf20Sopenharmony_ci struct devlink_region *region; 46318c2ecf20Sopenharmony_ci struct devlink_port *port; 46328c2ecf20Sopenharmony_ci int err = 0; 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 46358c2ecf20Sopenharmony_ci list_for_each_entry(region, &devlink->region_list, list) { 46368c2ecf20Sopenharmony_ci if (*idx < start) { 46378c2ecf20Sopenharmony_ci (*idx)++; 46388c2ecf20Sopenharmony_ci continue; 46398c2ecf20Sopenharmony_ci } 46408c2ecf20Sopenharmony_ci err = devlink_nl_region_fill(msg, devlink, 46418c2ecf20Sopenharmony_ci DEVLINK_CMD_REGION_GET, 46428c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 46438c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 46448c2ecf20Sopenharmony_ci NLM_F_MULTI, region); 46458c2ecf20Sopenharmony_ci if (err) 46468c2ecf20Sopenharmony_ci goto out; 46478c2ecf20Sopenharmony_ci (*idx)++; 46488c2ecf20Sopenharmony_ci } 46498c2ecf20Sopenharmony_ci 46508c2ecf20Sopenharmony_ci list_for_each_entry(port, &devlink->port_list, list) { 46518c2ecf20Sopenharmony_ci err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx, 46528c2ecf20Sopenharmony_ci start); 46538c2ecf20Sopenharmony_ci if (err) 46548c2ecf20Sopenharmony_ci goto out; 46558c2ecf20Sopenharmony_ci } 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ciout: 46588c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 46598c2ecf20Sopenharmony_ci return err; 46608c2ecf20Sopenharmony_ci} 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg, 46638c2ecf20Sopenharmony_ci struct netlink_callback *cb) 46648c2ecf20Sopenharmony_ci{ 46658c2ecf20Sopenharmony_ci struct devlink *devlink; 46668c2ecf20Sopenharmony_ci int start = cb->args[0]; 46678c2ecf20Sopenharmony_ci int idx = 0; 46688c2ecf20Sopenharmony_ci int err; 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 46718c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 46728c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 46738c2ecf20Sopenharmony_ci continue; 46748c2ecf20Sopenharmony_ci err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink, 46758c2ecf20Sopenharmony_ci &idx, start); 46768c2ecf20Sopenharmony_ci if (err) 46778c2ecf20Sopenharmony_ci goto out; 46788c2ecf20Sopenharmony_ci } 46798c2ecf20Sopenharmony_ciout: 46808c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 46818c2ecf20Sopenharmony_ci cb->args[0] = idx; 46828c2ecf20Sopenharmony_ci return msg->len; 46838c2ecf20Sopenharmony_ci} 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_del(struct sk_buff *skb, 46868c2ecf20Sopenharmony_ci struct genl_info *info) 46878c2ecf20Sopenharmony_ci{ 46888c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 46898c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 46908c2ecf20Sopenharmony_ci struct devlink_port *port = NULL; 46918c2ecf20Sopenharmony_ci struct devlink_region *region; 46928c2ecf20Sopenharmony_ci const char *region_name; 46938c2ecf20Sopenharmony_ci unsigned int index; 46948c2ecf20Sopenharmony_ci u32 snapshot_id; 46958c2ecf20Sopenharmony_ci 46968c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_REGION_NAME] || 46978c2ecf20Sopenharmony_ci !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) 46988c2ecf20Sopenharmony_ci return -EINVAL; 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 47018c2ecf20Sopenharmony_ci snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]); 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 47048c2ecf20Sopenharmony_ci index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci port = devlink_port_get_by_index(devlink, index); 47078c2ecf20Sopenharmony_ci if (!port) 47088c2ecf20Sopenharmony_ci return -ENODEV; 47098c2ecf20Sopenharmony_ci } 47108c2ecf20Sopenharmony_ci 47118c2ecf20Sopenharmony_ci if (port) 47128c2ecf20Sopenharmony_ci region = devlink_port_region_get_by_name(port, region_name); 47138c2ecf20Sopenharmony_ci else 47148c2ecf20Sopenharmony_ci region = devlink_region_get_by_name(devlink, region_name); 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci if (!region) 47178c2ecf20Sopenharmony_ci return -EINVAL; 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id); 47208c2ecf20Sopenharmony_ci if (!snapshot) 47218c2ecf20Sopenharmony_ci return -EINVAL; 47228c2ecf20Sopenharmony_ci 47238c2ecf20Sopenharmony_ci devlink_region_snapshot_del(region, snapshot); 47248c2ecf20Sopenharmony_ci return 0; 47258c2ecf20Sopenharmony_ci} 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_cistatic int 47288c2ecf20Sopenharmony_cidevlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) 47298c2ecf20Sopenharmony_ci{ 47308c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 47318c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 47328c2ecf20Sopenharmony_ci struct devlink_port *port = NULL; 47338c2ecf20Sopenharmony_ci struct nlattr *snapshot_id_attr; 47348c2ecf20Sopenharmony_ci struct devlink_region *region; 47358c2ecf20Sopenharmony_ci const char *region_name; 47368c2ecf20Sopenharmony_ci unsigned int index; 47378c2ecf20Sopenharmony_ci u32 snapshot_id; 47388c2ecf20Sopenharmony_ci u8 *data; 47398c2ecf20Sopenharmony_ci int err; 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) { 47428c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "No region name provided"); 47438c2ecf20Sopenharmony_ci return -EINVAL; 47448c2ecf20Sopenharmony_ci } 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 47478c2ecf20Sopenharmony_ci 47488c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 47498c2ecf20Sopenharmony_ci index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci port = devlink_port_get_by_index(devlink, index); 47528c2ecf20Sopenharmony_ci if (!port) 47538c2ecf20Sopenharmony_ci return -ENODEV; 47548c2ecf20Sopenharmony_ci } 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci if (port) 47578c2ecf20Sopenharmony_ci region = devlink_port_region_get_by_name(port, region_name); 47588c2ecf20Sopenharmony_ci else 47598c2ecf20Sopenharmony_ci region = devlink_region_get_by_name(devlink, region_name); 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci if (!region) { 47628c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist"); 47638c2ecf20Sopenharmony_ci return -EINVAL; 47648c2ecf20Sopenharmony_ci } 47658c2ecf20Sopenharmony_ci 47668c2ecf20Sopenharmony_ci if (!region->ops->snapshot) { 47678c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot"); 47688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 47698c2ecf20Sopenharmony_ci } 47708c2ecf20Sopenharmony_ci 47718c2ecf20Sopenharmony_ci if (region->cur_snapshots == region->max_snapshots) { 47728c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots"); 47738c2ecf20Sopenharmony_ci return -ENOSPC; 47748c2ecf20Sopenharmony_ci } 47758c2ecf20Sopenharmony_ci 47768c2ecf20Sopenharmony_ci snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]; 47778c2ecf20Sopenharmony_ci if (snapshot_id_attr) { 47788c2ecf20Sopenharmony_ci snapshot_id = nla_get_u32(snapshot_id_attr); 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci if (devlink_region_snapshot_get_by_id(region, snapshot_id)) { 47818c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use"); 47828c2ecf20Sopenharmony_ci return -EEXIST; 47838c2ecf20Sopenharmony_ci } 47848c2ecf20Sopenharmony_ci 47858c2ecf20Sopenharmony_ci err = __devlink_snapshot_id_insert(devlink, snapshot_id); 47868c2ecf20Sopenharmony_ci if (err) 47878c2ecf20Sopenharmony_ci return err; 47888c2ecf20Sopenharmony_ci } else { 47898c2ecf20Sopenharmony_ci err = __devlink_region_snapshot_id_get(devlink, &snapshot_id); 47908c2ecf20Sopenharmony_ci if (err) { 47918c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id"); 47928c2ecf20Sopenharmony_ci return err; 47938c2ecf20Sopenharmony_ci } 47948c2ecf20Sopenharmony_ci } 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci if (port) 47978c2ecf20Sopenharmony_ci err = region->port_ops->snapshot(port, region->port_ops, 47988c2ecf20Sopenharmony_ci info->extack, &data); 47998c2ecf20Sopenharmony_ci else 48008c2ecf20Sopenharmony_ci err = region->ops->snapshot(devlink, region->ops, 48018c2ecf20Sopenharmony_ci info->extack, &data); 48028c2ecf20Sopenharmony_ci if (err) 48038c2ecf20Sopenharmony_ci goto err_snapshot_capture; 48048c2ecf20Sopenharmony_ci 48058c2ecf20Sopenharmony_ci err = __devlink_region_snapshot_create(region, data, snapshot_id); 48068c2ecf20Sopenharmony_ci if (err) 48078c2ecf20Sopenharmony_ci goto err_snapshot_create; 48088c2ecf20Sopenharmony_ci 48098c2ecf20Sopenharmony_ci if (!snapshot_id_attr) { 48108c2ecf20Sopenharmony_ci struct sk_buff *msg; 48118c2ecf20Sopenharmony_ci 48128c2ecf20Sopenharmony_ci snapshot = devlink_region_snapshot_get_by_id(region, 48138c2ecf20Sopenharmony_ci snapshot_id); 48148c2ecf20Sopenharmony_ci if (WARN_ON(!snapshot)) 48158c2ecf20Sopenharmony_ci return -EINVAL; 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci msg = devlink_nl_region_notify_build(region, snapshot, 48188c2ecf20Sopenharmony_ci DEVLINK_CMD_REGION_NEW, 48198c2ecf20Sopenharmony_ci info->snd_portid, 48208c2ecf20Sopenharmony_ci info->snd_seq); 48218c2ecf20Sopenharmony_ci err = PTR_ERR_OR_ZERO(msg); 48228c2ecf20Sopenharmony_ci if (err) 48238c2ecf20Sopenharmony_ci goto err_notify; 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci err = genlmsg_reply(msg, info); 48268c2ecf20Sopenharmony_ci if (err) 48278c2ecf20Sopenharmony_ci goto err_notify; 48288c2ecf20Sopenharmony_ci } 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci return 0; 48318c2ecf20Sopenharmony_ci 48328c2ecf20Sopenharmony_cierr_snapshot_create: 48338c2ecf20Sopenharmony_ci region->ops->destructor(data); 48348c2ecf20Sopenharmony_cierr_snapshot_capture: 48358c2ecf20Sopenharmony_ci __devlink_snapshot_id_decrement(devlink, snapshot_id); 48368c2ecf20Sopenharmony_ci return err; 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_cierr_notify: 48398c2ecf20Sopenharmony_ci devlink_region_snapshot_del(region, snapshot); 48408c2ecf20Sopenharmony_ci return err; 48418c2ecf20Sopenharmony_ci} 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg, 48448c2ecf20Sopenharmony_ci struct devlink *devlink, 48458c2ecf20Sopenharmony_ci u8 *chunk, u32 chunk_size, 48468c2ecf20Sopenharmony_ci u64 addr) 48478c2ecf20Sopenharmony_ci{ 48488c2ecf20Sopenharmony_ci struct nlattr *chunk_attr; 48498c2ecf20Sopenharmony_ci int err; 48508c2ecf20Sopenharmony_ci 48518c2ecf20Sopenharmony_ci chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK); 48528c2ecf20Sopenharmony_ci if (!chunk_attr) 48538c2ecf20Sopenharmony_ci return -EINVAL; 48548c2ecf20Sopenharmony_ci 48558c2ecf20Sopenharmony_ci err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk); 48568c2ecf20Sopenharmony_ci if (err) 48578c2ecf20Sopenharmony_ci goto nla_put_failure; 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_ci err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr, 48608c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD); 48618c2ecf20Sopenharmony_ci if (err) 48628c2ecf20Sopenharmony_ci goto nla_put_failure; 48638c2ecf20Sopenharmony_ci 48648c2ecf20Sopenharmony_ci nla_nest_end(msg, chunk_attr); 48658c2ecf20Sopenharmony_ci return 0; 48668c2ecf20Sopenharmony_ci 48678c2ecf20Sopenharmony_cinla_put_failure: 48688c2ecf20Sopenharmony_ci nla_nest_cancel(msg, chunk_attr); 48698c2ecf20Sopenharmony_ci return err; 48708c2ecf20Sopenharmony_ci} 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci#define DEVLINK_REGION_READ_CHUNK_SIZE 256 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_cistatic int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb, 48758c2ecf20Sopenharmony_ci struct devlink *devlink, 48768c2ecf20Sopenharmony_ci struct devlink_region *region, 48778c2ecf20Sopenharmony_ci struct nlattr **attrs, 48788c2ecf20Sopenharmony_ci u64 start_offset, 48798c2ecf20Sopenharmony_ci u64 end_offset, 48808c2ecf20Sopenharmony_ci u64 *new_offset) 48818c2ecf20Sopenharmony_ci{ 48828c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot; 48838c2ecf20Sopenharmony_ci u64 curr_offset = start_offset; 48848c2ecf20Sopenharmony_ci u32 snapshot_id; 48858c2ecf20Sopenharmony_ci int err = 0; 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci *new_offset = start_offset; 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]); 48908c2ecf20Sopenharmony_ci snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id); 48918c2ecf20Sopenharmony_ci if (!snapshot) 48928c2ecf20Sopenharmony_ci return -EINVAL; 48938c2ecf20Sopenharmony_ci 48948c2ecf20Sopenharmony_ci while (curr_offset < end_offset) { 48958c2ecf20Sopenharmony_ci u32 data_size; 48968c2ecf20Sopenharmony_ci u8 *data; 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE) 48998c2ecf20Sopenharmony_ci data_size = end_offset - curr_offset; 49008c2ecf20Sopenharmony_ci else 49018c2ecf20Sopenharmony_ci data_size = DEVLINK_REGION_READ_CHUNK_SIZE; 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci data = &snapshot->data[curr_offset]; 49048c2ecf20Sopenharmony_ci err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink, 49058c2ecf20Sopenharmony_ci data, data_size, 49068c2ecf20Sopenharmony_ci curr_offset); 49078c2ecf20Sopenharmony_ci if (err) 49088c2ecf20Sopenharmony_ci break; 49098c2ecf20Sopenharmony_ci 49108c2ecf20Sopenharmony_ci curr_offset += data_size; 49118c2ecf20Sopenharmony_ci } 49128c2ecf20Sopenharmony_ci *new_offset = curr_offset; 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci return err; 49158c2ecf20Sopenharmony_ci} 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, 49188c2ecf20Sopenharmony_ci struct netlink_callback *cb) 49198c2ecf20Sopenharmony_ci{ 49208c2ecf20Sopenharmony_ci const struct genl_dumpit_info *info = genl_dumpit_info(cb); 49218c2ecf20Sopenharmony_ci u64 ret_offset, start_offset, end_offset = U64_MAX; 49228c2ecf20Sopenharmony_ci struct nlattr **attrs = info->attrs; 49238c2ecf20Sopenharmony_ci struct devlink_port *port = NULL; 49248c2ecf20Sopenharmony_ci struct devlink_region *region; 49258c2ecf20Sopenharmony_ci struct nlattr *chunks_attr; 49268c2ecf20Sopenharmony_ci const char *region_name; 49278c2ecf20Sopenharmony_ci struct devlink *devlink; 49288c2ecf20Sopenharmony_ci unsigned int index; 49298c2ecf20Sopenharmony_ci void *hdr; 49308c2ecf20Sopenharmony_ci int err; 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci start_offset = *((u64 *)&cb->args[0]); 49338c2ecf20Sopenharmony_ci 49348c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 49358c2ecf20Sopenharmony_ci devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs); 49368c2ecf20Sopenharmony_ci if (IS_ERR(devlink)) { 49378c2ecf20Sopenharmony_ci err = PTR_ERR(devlink); 49388c2ecf20Sopenharmony_ci goto out_dev; 49398c2ecf20Sopenharmony_ci } 49408c2ecf20Sopenharmony_ci 49418c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 49428c2ecf20Sopenharmony_ci 49438c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_REGION_NAME] || 49448c2ecf20Sopenharmony_ci !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) { 49458c2ecf20Sopenharmony_ci err = -EINVAL; 49468c2ecf20Sopenharmony_ci goto out_unlock; 49478c2ecf20Sopenharmony_ci } 49488c2ecf20Sopenharmony_ci 49498c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 49508c2ecf20Sopenharmony_ci index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 49518c2ecf20Sopenharmony_ci 49528c2ecf20Sopenharmony_ci port = devlink_port_get_by_index(devlink, index); 49538c2ecf20Sopenharmony_ci if (!port) { 49548c2ecf20Sopenharmony_ci err = -ENODEV; 49558c2ecf20Sopenharmony_ci goto out_unlock; 49568c2ecf20Sopenharmony_ci } 49578c2ecf20Sopenharmony_ci } 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci if (port) 49628c2ecf20Sopenharmony_ci region = devlink_port_region_get_by_name(port, region_name); 49638c2ecf20Sopenharmony_ci else 49648c2ecf20Sopenharmony_ci region = devlink_region_get_by_name(devlink, region_name); 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci if (!region) { 49678c2ecf20Sopenharmony_ci err = -EINVAL; 49688c2ecf20Sopenharmony_ci goto out_unlock; 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] && 49728c2ecf20Sopenharmony_ci attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) { 49738c2ecf20Sopenharmony_ci if (!start_offset) 49748c2ecf20Sopenharmony_ci start_offset = 49758c2ecf20Sopenharmony_ci nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]); 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]); 49788c2ecf20Sopenharmony_ci end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]); 49798c2ecf20Sopenharmony_ci } 49808c2ecf20Sopenharmony_ci 49818c2ecf20Sopenharmony_ci if (end_offset > region->size) 49828c2ecf20Sopenharmony_ci end_offset = region->size; 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci /* return 0 if there is no further data to read */ 49858c2ecf20Sopenharmony_ci if (start_offset == end_offset) { 49868c2ecf20Sopenharmony_ci err = 0; 49878c2ecf20Sopenharmony_ci goto out_unlock; 49888c2ecf20Sopenharmony_ci } 49898c2ecf20Sopenharmony_ci 49908c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 49918c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, 49928c2ecf20Sopenharmony_ci DEVLINK_CMD_REGION_READ); 49938c2ecf20Sopenharmony_ci if (!hdr) { 49948c2ecf20Sopenharmony_ci err = -EMSGSIZE; 49958c2ecf20Sopenharmony_ci goto out_unlock; 49968c2ecf20Sopenharmony_ci } 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_ci err = devlink_nl_put_handle(skb, devlink); 49998c2ecf20Sopenharmony_ci if (err) 50008c2ecf20Sopenharmony_ci goto nla_put_failure; 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci if (region->port) { 50038c2ecf20Sopenharmony_ci err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, 50048c2ecf20Sopenharmony_ci region->port->index); 50058c2ecf20Sopenharmony_ci if (err) 50068c2ecf20Sopenharmony_ci goto nla_put_failure; 50078c2ecf20Sopenharmony_ci } 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_ci err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name); 50108c2ecf20Sopenharmony_ci if (err) 50118c2ecf20Sopenharmony_ci goto nla_put_failure; 50128c2ecf20Sopenharmony_ci 50138c2ecf20Sopenharmony_ci chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS); 50148c2ecf20Sopenharmony_ci if (!chunks_attr) { 50158c2ecf20Sopenharmony_ci err = -EMSGSIZE; 50168c2ecf20Sopenharmony_ci goto nla_put_failure; 50178c2ecf20Sopenharmony_ci } 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci err = devlink_nl_region_read_snapshot_fill(skb, devlink, 50208c2ecf20Sopenharmony_ci region, attrs, 50218c2ecf20Sopenharmony_ci start_offset, 50228c2ecf20Sopenharmony_ci end_offset, &ret_offset); 50238c2ecf20Sopenharmony_ci 50248c2ecf20Sopenharmony_ci if (err && err != -EMSGSIZE) 50258c2ecf20Sopenharmony_ci goto nla_put_failure; 50268c2ecf20Sopenharmony_ci 50278c2ecf20Sopenharmony_ci /* Check if there was any progress done to prevent infinite loop */ 50288c2ecf20Sopenharmony_ci if (ret_offset == start_offset) { 50298c2ecf20Sopenharmony_ci err = -EINVAL; 50308c2ecf20Sopenharmony_ci goto nla_put_failure; 50318c2ecf20Sopenharmony_ci } 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci *((u64 *)&cb->args[0]) = ret_offset; 50348c2ecf20Sopenharmony_ci 50358c2ecf20Sopenharmony_ci nla_nest_end(skb, chunks_attr); 50368c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 50378c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 50388c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 50398c2ecf20Sopenharmony_ci 50408c2ecf20Sopenharmony_ci return skb->len; 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_cinla_put_failure: 50438c2ecf20Sopenharmony_ci genlmsg_cancel(skb, hdr); 50448c2ecf20Sopenharmony_ciout_unlock: 50458c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 50468c2ecf20Sopenharmony_ciout_dev: 50478c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 50488c2ecf20Sopenharmony_ci return err; 50498c2ecf20Sopenharmony_ci} 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_cistruct devlink_info_req { 50528c2ecf20Sopenharmony_ci struct sk_buff *msg; 50538c2ecf20Sopenharmony_ci}; 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ciint devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) 50568c2ecf20Sopenharmony_ci{ 50578c2ecf20Sopenharmony_ci return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); 50588c2ecf20Sopenharmony_ci} 50598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_driver_name_put); 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ciint devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn) 50628c2ecf20Sopenharmony_ci{ 50638c2ecf20Sopenharmony_ci return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn); 50648c2ecf20Sopenharmony_ci} 50658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_serial_number_put); 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_ciint devlink_info_board_serial_number_put(struct devlink_info_req *req, 50688c2ecf20Sopenharmony_ci const char *bsn) 50698c2ecf20Sopenharmony_ci{ 50708c2ecf20Sopenharmony_ci return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER, 50718c2ecf20Sopenharmony_ci bsn); 50728c2ecf20Sopenharmony_ci} 50738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put); 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_cistatic int devlink_info_version_put(struct devlink_info_req *req, int attr, 50768c2ecf20Sopenharmony_ci const char *version_name, 50778c2ecf20Sopenharmony_ci const char *version_value) 50788c2ecf20Sopenharmony_ci{ 50798c2ecf20Sopenharmony_ci struct nlattr *nest; 50808c2ecf20Sopenharmony_ci int err; 50818c2ecf20Sopenharmony_ci 50828c2ecf20Sopenharmony_ci nest = nla_nest_start_noflag(req->msg, attr); 50838c2ecf20Sopenharmony_ci if (!nest) 50848c2ecf20Sopenharmony_ci return -EMSGSIZE; 50858c2ecf20Sopenharmony_ci 50868c2ecf20Sopenharmony_ci err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME, 50878c2ecf20Sopenharmony_ci version_name); 50888c2ecf20Sopenharmony_ci if (err) 50898c2ecf20Sopenharmony_ci goto nla_put_failure; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE, 50928c2ecf20Sopenharmony_ci version_value); 50938c2ecf20Sopenharmony_ci if (err) 50948c2ecf20Sopenharmony_ci goto nla_put_failure; 50958c2ecf20Sopenharmony_ci 50968c2ecf20Sopenharmony_ci nla_nest_end(req->msg, nest); 50978c2ecf20Sopenharmony_ci 50988c2ecf20Sopenharmony_ci return 0; 50998c2ecf20Sopenharmony_ci 51008c2ecf20Sopenharmony_cinla_put_failure: 51018c2ecf20Sopenharmony_ci nla_nest_cancel(req->msg, nest); 51028c2ecf20Sopenharmony_ci return err; 51038c2ecf20Sopenharmony_ci} 51048c2ecf20Sopenharmony_ci 51058c2ecf20Sopenharmony_ciint devlink_info_version_fixed_put(struct devlink_info_req *req, 51068c2ecf20Sopenharmony_ci const char *version_name, 51078c2ecf20Sopenharmony_ci const char *version_value) 51088c2ecf20Sopenharmony_ci{ 51098c2ecf20Sopenharmony_ci return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED, 51108c2ecf20Sopenharmony_ci version_name, version_value); 51118c2ecf20Sopenharmony_ci} 51128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_fixed_put); 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ciint devlink_info_version_stored_put(struct devlink_info_req *req, 51158c2ecf20Sopenharmony_ci const char *version_name, 51168c2ecf20Sopenharmony_ci const char *version_value) 51178c2ecf20Sopenharmony_ci{ 51188c2ecf20Sopenharmony_ci return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED, 51198c2ecf20Sopenharmony_ci version_name, version_value); 51208c2ecf20Sopenharmony_ci} 51218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_stored_put); 51228c2ecf20Sopenharmony_ci 51238c2ecf20Sopenharmony_ciint devlink_info_version_running_put(struct devlink_info_req *req, 51248c2ecf20Sopenharmony_ci const char *version_name, 51258c2ecf20Sopenharmony_ci const char *version_value) 51268c2ecf20Sopenharmony_ci{ 51278c2ecf20Sopenharmony_ci return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING, 51288c2ecf20Sopenharmony_ci version_name, version_value); 51298c2ecf20Sopenharmony_ci} 51308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_running_put); 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_cistatic int 51338c2ecf20Sopenharmony_cidevlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, 51348c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 51358c2ecf20Sopenharmony_ci u32 seq, int flags, struct netlink_ext_ack *extack) 51368c2ecf20Sopenharmony_ci{ 51378c2ecf20Sopenharmony_ci struct devlink_info_req req; 51388c2ecf20Sopenharmony_ci void *hdr; 51398c2ecf20Sopenharmony_ci int err; 51408c2ecf20Sopenharmony_ci 51418c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 51428c2ecf20Sopenharmony_ci if (!hdr) 51438c2ecf20Sopenharmony_ci return -EMSGSIZE; 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_ci err = -EMSGSIZE; 51468c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 51478c2ecf20Sopenharmony_ci goto err_cancel_msg; 51488c2ecf20Sopenharmony_ci 51498c2ecf20Sopenharmony_ci req.msg = msg; 51508c2ecf20Sopenharmony_ci err = devlink->ops->info_get(devlink, &req, extack); 51518c2ecf20Sopenharmony_ci if (err) 51528c2ecf20Sopenharmony_ci goto err_cancel_msg; 51538c2ecf20Sopenharmony_ci 51548c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 51558c2ecf20Sopenharmony_ci return 0; 51568c2ecf20Sopenharmony_ci 51578c2ecf20Sopenharmony_cierr_cancel_msg: 51588c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 51598c2ecf20Sopenharmony_ci return err; 51608c2ecf20Sopenharmony_ci} 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, 51638c2ecf20Sopenharmony_ci struct genl_info *info) 51648c2ecf20Sopenharmony_ci{ 51658c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 51668c2ecf20Sopenharmony_ci struct sk_buff *msg; 51678c2ecf20Sopenharmony_ci int err; 51688c2ecf20Sopenharmony_ci 51698c2ecf20Sopenharmony_ci if (!devlink->ops->info_get) 51708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 51738c2ecf20Sopenharmony_ci if (!msg) 51748c2ecf20Sopenharmony_ci return -ENOMEM; 51758c2ecf20Sopenharmony_ci 51768c2ecf20Sopenharmony_ci err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, 51778c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0, 51788c2ecf20Sopenharmony_ci info->extack); 51798c2ecf20Sopenharmony_ci if (err) { 51808c2ecf20Sopenharmony_ci nlmsg_free(msg); 51818c2ecf20Sopenharmony_ci return err; 51828c2ecf20Sopenharmony_ci } 51838c2ecf20Sopenharmony_ci 51848c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 51858c2ecf20Sopenharmony_ci} 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg, 51888c2ecf20Sopenharmony_ci struct netlink_callback *cb) 51898c2ecf20Sopenharmony_ci{ 51908c2ecf20Sopenharmony_ci struct devlink *devlink; 51918c2ecf20Sopenharmony_ci int start = cb->args[0]; 51928c2ecf20Sopenharmony_ci int idx = 0; 51938c2ecf20Sopenharmony_ci int err = 0; 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 51968c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 51978c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 51988c2ecf20Sopenharmony_ci continue; 51998c2ecf20Sopenharmony_ci if (idx < start) { 52008c2ecf20Sopenharmony_ci idx++; 52018c2ecf20Sopenharmony_ci continue; 52028c2ecf20Sopenharmony_ci } 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci if (!devlink->ops->info_get) { 52058c2ecf20Sopenharmony_ci idx++; 52068c2ecf20Sopenharmony_ci continue; 52078c2ecf20Sopenharmony_ci } 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 52108c2ecf20Sopenharmony_ci err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, 52118c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 52128c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, NLM_F_MULTI, 52138c2ecf20Sopenharmony_ci cb->extack); 52148c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 52158c2ecf20Sopenharmony_ci if (err == -EOPNOTSUPP) 52168c2ecf20Sopenharmony_ci err = 0; 52178c2ecf20Sopenharmony_ci else if (err) 52188c2ecf20Sopenharmony_ci break; 52198c2ecf20Sopenharmony_ci idx++; 52208c2ecf20Sopenharmony_ci } 52218c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 52228c2ecf20Sopenharmony_ci 52238c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 52248c2ecf20Sopenharmony_ci return err; 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci cb->args[0] = idx; 52278c2ecf20Sopenharmony_ci return msg->len; 52288c2ecf20Sopenharmony_ci} 52298c2ecf20Sopenharmony_ci 52308c2ecf20Sopenharmony_cistruct devlink_fmsg_item { 52318c2ecf20Sopenharmony_ci struct list_head list; 52328c2ecf20Sopenharmony_ci int attrtype; 52338c2ecf20Sopenharmony_ci u8 nla_type; 52348c2ecf20Sopenharmony_ci u16 len; 52358c2ecf20Sopenharmony_ci int value[]; 52368c2ecf20Sopenharmony_ci}; 52378c2ecf20Sopenharmony_ci 52388c2ecf20Sopenharmony_cistruct devlink_fmsg { 52398c2ecf20Sopenharmony_ci struct list_head item_list; 52408c2ecf20Sopenharmony_ci bool putting_binary; /* This flag forces enclosing of binary data 52418c2ecf20Sopenharmony_ci * in an array brackets. It forces using 52428c2ecf20Sopenharmony_ci * of designated API: 52438c2ecf20Sopenharmony_ci * devlink_fmsg_binary_pair_nest_start() 52448c2ecf20Sopenharmony_ci * devlink_fmsg_binary_pair_nest_end() 52458c2ecf20Sopenharmony_ci */ 52468c2ecf20Sopenharmony_ci}; 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_cistatic struct devlink_fmsg *devlink_fmsg_alloc(void) 52498c2ecf20Sopenharmony_ci{ 52508c2ecf20Sopenharmony_ci struct devlink_fmsg *fmsg; 52518c2ecf20Sopenharmony_ci 52528c2ecf20Sopenharmony_ci fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL); 52538c2ecf20Sopenharmony_ci if (!fmsg) 52548c2ecf20Sopenharmony_ci return NULL; 52558c2ecf20Sopenharmony_ci 52568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fmsg->item_list); 52578c2ecf20Sopenharmony_ci 52588c2ecf20Sopenharmony_ci return fmsg; 52598c2ecf20Sopenharmony_ci} 52608c2ecf20Sopenharmony_ci 52618c2ecf20Sopenharmony_cistatic void devlink_fmsg_free(struct devlink_fmsg *fmsg) 52628c2ecf20Sopenharmony_ci{ 52638c2ecf20Sopenharmony_ci struct devlink_fmsg_item *item, *tmp; 52648c2ecf20Sopenharmony_ci 52658c2ecf20Sopenharmony_ci list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) { 52668c2ecf20Sopenharmony_ci list_del(&item->list); 52678c2ecf20Sopenharmony_ci kfree(item); 52688c2ecf20Sopenharmony_ci } 52698c2ecf20Sopenharmony_ci kfree(fmsg); 52708c2ecf20Sopenharmony_ci} 52718c2ecf20Sopenharmony_ci 52728c2ecf20Sopenharmony_cistatic int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg, 52738c2ecf20Sopenharmony_ci int attrtype) 52748c2ecf20Sopenharmony_ci{ 52758c2ecf20Sopenharmony_ci struct devlink_fmsg_item *item; 52768c2ecf20Sopenharmony_ci 52778c2ecf20Sopenharmony_ci item = kzalloc(sizeof(*item), GFP_KERNEL); 52788c2ecf20Sopenharmony_ci if (!item) 52798c2ecf20Sopenharmony_ci return -ENOMEM; 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_ci item->attrtype = attrtype; 52828c2ecf20Sopenharmony_ci list_add_tail(&item->list, &fmsg->item_list); 52838c2ecf20Sopenharmony_ci 52848c2ecf20Sopenharmony_ci return 0; 52858c2ecf20Sopenharmony_ci} 52868c2ecf20Sopenharmony_ci 52878c2ecf20Sopenharmony_ciint devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg) 52888c2ecf20Sopenharmony_ci{ 52898c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 52908c2ecf20Sopenharmony_ci return -EINVAL; 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_ci return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START); 52938c2ecf20Sopenharmony_ci} 52948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start); 52958c2ecf20Sopenharmony_ci 52968c2ecf20Sopenharmony_cistatic int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg) 52978c2ecf20Sopenharmony_ci{ 52988c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 52998c2ecf20Sopenharmony_ci return -EINVAL; 53008c2ecf20Sopenharmony_ci 53018c2ecf20Sopenharmony_ci return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END); 53028c2ecf20Sopenharmony_ci} 53038c2ecf20Sopenharmony_ci 53048c2ecf20Sopenharmony_ciint devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg) 53058c2ecf20Sopenharmony_ci{ 53068c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53078c2ecf20Sopenharmony_ci return -EINVAL; 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_ci return devlink_fmsg_nest_end(fmsg); 53108c2ecf20Sopenharmony_ci} 53118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end); 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN) 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_cistatic int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name) 53168c2ecf20Sopenharmony_ci{ 53178c2ecf20Sopenharmony_ci struct devlink_fmsg_item *item; 53188c2ecf20Sopenharmony_ci 53198c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53208c2ecf20Sopenharmony_ci return -EINVAL; 53218c2ecf20Sopenharmony_ci 53228c2ecf20Sopenharmony_ci if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE) 53238c2ecf20Sopenharmony_ci return -EMSGSIZE; 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL); 53268c2ecf20Sopenharmony_ci if (!item) 53278c2ecf20Sopenharmony_ci return -ENOMEM; 53288c2ecf20Sopenharmony_ci 53298c2ecf20Sopenharmony_ci item->nla_type = NLA_NUL_STRING; 53308c2ecf20Sopenharmony_ci item->len = strlen(name) + 1; 53318c2ecf20Sopenharmony_ci item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME; 53328c2ecf20Sopenharmony_ci memcpy(&item->value, name, item->len); 53338c2ecf20Sopenharmony_ci list_add_tail(&item->list, &fmsg->item_list); 53348c2ecf20Sopenharmony_ci 53358c2ecf20Sopenharmony_ci return 0; 53368c2ecf20Sopenharmony_ci} 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ciint devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name) 53398c2ecf20Sopenharmony_ci{ 53408c2ecf20Sopenharmony_ci int err; 53418c2ecf20Sopenharmony_ci 53428c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53438c2ecf20Sopenharmony_ci return -EINVAL; 53448c2ecf20Sopenharmony_ci 53458c2ecf20Sopenharmony_ci err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START); 53468c2ecf20Sopenharmony_ci if (err) 53478c2ecf20Sopenharmony_ci return err; 53488c2ecf20Sopenharmony_ci 53498c2ecf20Sopenharmony_ci err = devlink_fmsg_put_name(fmsg, name); 53508c2ecf20Sopenharmony_ci if (err) 53518c2ecf20Sopenharmony_ci return err; 53528c2ecf20Sopenharmony_ci 53538c2ecf20Sopenharmony_ci return 0; 53548c2ecf20Sopenharmony_ci} 53558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start); 53568c2ecf20Sopenharmony_ci 53578c2ecf20Sopenharmony_ciint devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg) 53588c2ecf20Sopenharmony_ci{ 53598c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53608c2ecf20Sopenharmony_ci return -EINVAL; 53618c2ecf20Sopenharmony_ci 53628c2ecf20Sopenharmony_ci return devlink_fmsg_nest_end(fmsg); 53638c2ecf20Sopenharmony_ci} 53648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end); 53658c2ecf20Sopenharmony_ci 53668c2ecf20Sopenharmony_ciint devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg, 53678c2ecf20Sopenharmony_ci const char *name) 53688c2ecf20Sopenharmony_ci{ 53698c2ecf20Sopenharmony_ci int err; 53708c2ecf20Sopenharmony_ci 53718c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53728c2ecf20Sopenharmony_ci return -EINVAL; 53738c2ecf20Sopenharmony_ci 53748c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 53758c2ecf20Sopenharmony_ci if (err) 53768c2ecf20Sopenharmony_ci return err; 53778c2ecf20Sopenharmony_ci 53788c2ecf20Sopenharmony_ci err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START); 53798c2ecf20Sopenharmony_ci if (err) 53808c2ecf20Sopenharmony_ci return err; 53818c2ecf20Sopenharmony_ci 53828c2ecf20Sopenharmony_ci return 0; 53838c2ecf20Sopenharmony_ci} 53848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start); 53858c2ecf20Sopenharmony_ci 53868c2ecf20Sopenharmony_ciint devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg) 53878c2ecf20Sopenharmony_ci{ 53888c2ecf20Sopenharmony_ci int err; 53898c2ecf20Sopenharmony_ci 53908c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 53918c2ecf20Sopenharmony_ci return -EINVAL; 53928c2ecf20Sopenharmony_ci 53938c2ecf20Sopenharmony_ci err = devlink_fmsg_nest_end(fmsg); 53948c2ecf20Sopenharmony_ci if (err) 53958c2ecf20Sopenharmony_ci return err; 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci err = devlink_fmsg_nest_end(fmsg); 53988c2ecf20Sopenharmony_ci if (err) 53998c2ecf20Sopenharmony_ci return err; 54008c2ecf20Sopenharmony_ci 54018c2ecf20Sopenharmony_ci return 0; 54028c2ecf20Sopenharmony_ci} 54038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end); 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg, 54068c2ecf20Sopenharmony_ci const char *name) 54078c2ecf20Sopenharmony_ci{ 54088c2ecf20Sopenharmony_ci int err; 54098c2ecf20Sopenharmony_ci 54108c2ecf20Sopenharmony_ci err = devlink_fmsg_arr_pair_nest_start(fmsg, name); 54118c2ecf20Sopenharmony_ci if (err) 54128c2ecf20Sopenharmony_ci return err; 54138c2ecf20Sopenharmony_ci 54148c2ecf20Sopenharmony_ci fmsg->putting_binary = true; 54158c2ecf20Sopenharmony_ci return err; 54168c2ecf20Sopenharmony_ci} 54178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start); 54188c2ecf20Sopenharmony_ci 54198c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg) 54208c2ecf20Sopenharmony_ci{ 54218c2ecf20Sopenharmony_ci if (!fmsg->putting_binary) 54228c2ecf20Sopenharmony_ci return -EINVAL; 54238c2ecf20Sopenharmony_ci 54248c2ecf20Sopenharmony_ci fmsg->putting_binary = false; 54258c2ecf20Sopenharmony_ci return devlink_fmsg_arr_pair_nest_end(fmsg); 54268c2ecf20Sopenharmony_ci} 54278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end); 54288c2ecf20Sopenharmony_ci 54298c2ecf20Sopenharmony_cistatic int devlink_fmsg_put_value(struct devlink_fmsg *fmsg, 54308c2ecf20Sopenharmony_ci const void *value, u16 value_len, 54318c2ecf20Sopenharmony_ci u8 value_nla_type) 54328c2ecf20Sopenharmony_ci{ 54338c2ecf20Sopenharmony_ci struct devlink_fmsg_item *item; 54348c2ecf20Sopenharmony_ci 54358c2ecf20Sopenharmony_ci if (value_len > DEVLINK_FMSG_MAX_SIZE) 54368c2ecf20Sopenharmony_ci return -EMSGSIZE; 54378c2ecf20Sopenharmony_ci 54388c2ecf20Sopenharmony_ci item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL); 54398c2ecf20Sopenharmony_ci if (!item) 54408c2ecf20Sopenharmony_ci return -ENOMEM; 54418c2ecf20Sopenharmony_ci 54428c2ecf20Sopenharmony_ci item->nla_type = value_nla_type; 54438c2ecf20Sopenharmony_ci item->len = value_len; 54448c2ecf20Sopenharmony_ci item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA; 54458c2ecf20Sopenharmony_ci memcpy(&item->value, value, item->len); 54468c2ecf20Sopenharmony_ci list_add_tail(&item->list, &fmsg->item_list); 54478c2ecf20Sopenharmony_ci 54488c2ecf20Sopenharmony_ci return 0; 54498c2ecf20Sopenharmony_ci} 54508c2ecf20Sopenharmony_ci 54518c2ecf20Sopenharmony_ciint devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value) 54528c2ecf20Sopenharmony_ci{ 54538c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 54548c2ecf20Sopenharmony_ci return -EINVAL; 54558c2ecf20Sopenharmony_ci 54568c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG); 54578c2ecf20Sopenharmony_ci} 54588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_bool_put); 54598c2ecf20Sopenharmony_ci 54608c2ecf20Sopenharmony_ciint devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value) 54618c2ecf20Sopenharmony_ci{ 54628c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 54638c2ecf20Sopenharmony_ci return -EINVAL; 54648c2ecf20Sopenharmony_ci 54658c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8); 54668c2ecf20Sopenharmony_ci} 54678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u8_put); 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_ciint devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value) 54708c2ecf20Sopenharmony_ci{ 54718c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 54728c2ecf20Sopenharmony_ci return -EINVAL; 54738c2ecf20Sopenharmony_ci 54748c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32); 54758c2ecf20Sopenharmony_ci} 54768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u32_put); 54778c2ecf20Sopenharmony_ci 54788c2ecf20Sopenharmony_ciint devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value) 54798c2ecf20Sopenharmony_ci{ 54808c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 54818c2ecf20Sopenharmony_ci return -EINVAL; 54828c2ecf20Sopenharmony_ci 54838c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64); 54848c2ecf20Sopenharmony_ci} 54858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u64_put); 54868c2ecf20Sopenharmony_ci 54878c2ecf20Sopenharmony_ciint devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value) 54888c2ecf20Sopenharmony_ci{ 54898c2ecf20Sopenharmony_ci if (fmsg->putting_binary) 54908c2ecf20Sopenharmony_ci return -EINVAL; 54918c2ecf20Sopenharmony_ci 54928c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1, 54938c2ecf20Sopenharmony_ci NLA_NUL_STRING); 54948c2ecf20Sopenharmony_ci} 54958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_string_put); 54968c2ecf20Sopenharmony_ci 54978c2ecf20Sopenharmony_ciint devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value, 54988c2ecf20Sopenharmony_ci u16 value_len) 54998c2ecf20Sopenharmony_ci{ 55008c2ecf20Sopenharmony_ci if (!fmsg->putting_binary) 55018c2ecf20Sopenharmony_ci return -EINVAL; 55028c2ecf20Sopenharmony_ci 55038c2ecf20Sopenharmony_ci return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY); 55048c2ecf20Sopenharmony_ci} 55058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_put); 55068c2ecf20Sopenharmony_ci 55078c2ecf20Sopenharmony_ciint devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name, 55088c2ecf20Sopenharmony_ci bool value) 55098c2ecf20Sopenharmony_ci{ 55108c2ecf20Sopenharmony_ci int err; 55118c2ecf20Sopenharmony_ci 55128c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 55138c2ecf20Sopenharmony_ci if (err) 55148c2ecf20Sopenharmony_ci return err; 55158c2ecf20Sopenharmony_ci 55168c2ecf20Sopenharmony_ci err = devlink_fmsg_bool_put(fmsg, value); 55178c2ecf20Sopenharmony_ci if (err) 55188c2ecf20Sopenharmony_ci return err; 55198c2ecf20Sopenharmony_ci 55208c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_end(fmsg); 55218c2ecf20Sopenharmony_ci if (err) 55228c2ecf20Sopenharmony_ci return err; 55238c2ecf20Sopenharmony_ci 55248c2ecf20Sopenharmony_ci return 0; 55258c2ecf20Sopenharmony_ci} 55268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put); 55278c2ecf20Sopenharmony_ci 55288c2ecf20Sopenharmony_ciint devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name, 55298c2ecf20Sopenharmony_ci u8 value) 55308c2ecf20Sopenharmony_ci{ 55318c2ecf20Sopenharmony_ci int err; 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 55348c2ecf20Sopenharmony_ci if (err) 55358c2ecf20Sopenharmony_ci return err; 55368c2ecf20Sopenharmony_ci 55378c2ecf20Sopenharmony_ci err = devlink_fmsg_u8_put(fmsg, value); 55388c2ecf20Sopenharmony_ci if (err) 55398c2ecf20Sopenharmony_ci return err; 55408c2ecf20Sopenharmony_ci 55418c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_end(fmsg); 55428c2ecf20Sopenharmony_ci if (err) 55438c2ecf20Sopenharmony_ci return err; 55448c2ecf20Sopenharmony_ci 55458c2ecf20Sopenharmony_ci return 0; 55468c2ecf20Sopenharmony_ci} 55478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put); 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_ciint devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name, 55508c2ecf20Sopenharmony_ci u32 value) 55518c2ecf20Sopenharmony_ci{ 55528c2ecf20Sopenharmony_ci int err; 55538c2ecf20Sopenharmony_ci 55548c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 55558c2ecf20Sopenharmony_ci if (err) 55568c2ecf20Sopenharmony_ci return err; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci err = devlink_fmsg_u32_put(fmsg, value); 55598c2ecf20Sopenharmony_ci if (err) 55608c2ecf20Sopenharmony_ci return err; 55618c2ecf20Sopenharmony_ci 55628c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_end(fmsg); 55638c2ecf20Sopenharmony_ci if (err) 55648c2ecf20Sopenharmony_ci return err; 55658c2ecf20Sopenharmony_ci 55668c2ecf20Sopenharmony_ci return 0; 55678c2ecf20Sopenharmony_ci} 55688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put); 55698c2ecf20Sopenharmony_ci 55708c2ecf20Sopenharmony_ciint devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name, 55718c2ecf20Sopenharmony_ci u64 value) 55728c2ecf20Sopenharmony_ci{ 55738c2ecf20Sopenharmony_ci int err; 55748c2ecf20Sopenharmony_ci 55758c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 55768c2ecf20Sopenharmony_ci if (err) 55778c2ecf20Sopenharmony_ci return err; 55788c2ecf20Sopenharmony_ci 55798c2ecf20Sopenharmony_ci err = devlink_fmsg_u64_put(fmsg, value); 55808c2ecf20Sopenharmony_ci if (err) 55818c2ecf20Sopenharmony_ci return err; 55828c2ecf20Sopenharmony_ci 55838c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_end(fmsg); 55848c2ecf20Sopenharmony_ci if (err) 55858c2ecf20Sopenharmony_ci return err; 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_ci return 0; 55888c2ecf20Sopenharmony_ci} 55898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put); 55908c2ecf20Sopenharmony_ci 55918c2ecf20Sopenharmony_ciint devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name, 55928c2ecf20Sopenharmony_ci const char *value) 55938c2ecf20Sopenharmony_ci{ 55948c2ecf20Sopenharmony_ci int err; 55958c2ecf20Sopenharmony_ci 55968c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_start(fmsg, name); 55978c2ecf20Sopenharmony_ci if (err) 55988c2ecf20Sopenharmony_ci return err; 55998c2ecf20Sopenharmony_ci 56008c2ecf20Sopenharmony_ci err = devlink_fmsg_string_put(fmsg, value); 56018c2ecf20Sopenharmony_ci if (err) 56028c2ecf20Sopenharmony_ci return err; 56038c2ecf20Sopenharmony_ci 56048c2ecf20Sopenharmony_ci err = devlink_fmsg_pair_nest_end(fmsg); 56058c2ecf20Sopenharmony_ci if (err) 56068c2ecf20Sopenharmony_ci return err; 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_ci return 0; 56098c2ecf20Sopenharmony_ci} 56108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put); 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name, 56138c2ecf20Sopenharmony_ci const void *value, u32 value_len) 56148c2ecf20Sopenharmony_ci{ 56158c2ecf20Sopenharmony_ci u32 data_size; 56168c2ecf20Sopenharmony_ci int end_err; 56178c2ecf20Sopenharmony_ci u32 offset; 56188c2ecf20Sopenharmony_ci int err; 56198c2ecf20Sopenharmony_ci 56208c2ecf20Sopenharmony_ci err = devlink_fmsg_binary_pair_nest_start(fmsg, name); 56218c2ecf20Sopenharmony_ci if (err) 56228c2ecf20Sopenharmony_ci return err; 56238c2ecf20Sopenharmony_ci 56248c2ecf20Sopenharmony_ci for (offset = 0; offset < value_len; offset += data_size) { 56258c2ecf20Sopenharmony_ci data_size = value_len - offset; 56268c2ecf20Sopenharmony_ci if (data_size > DEVLINK_FMSG_MAX_SIZE) 56278c2ecf20Sopenharmony_ci data_size = DEVLINK_FMSG_MAX_SIZE; 56288c2ecf20Sopenharmony_ci err = devlink_fmsg_binary_put(fmsg, value + offset, data_size); 56298c2ecf20Sopenharmony_ci if (err) 56308c2ecf20Sopenharmony_ci break; 56318c2ecf20Sopenharmony_ci /* Exit from loop with a break (instead of 56328c2ecf20Sopenharmony_ci * return) to make sure putting_binary is turned off in 56338c2ecf20Sopenharmony_ci * devlink_fmsg_binary_pair_nest_end 56348c2ecf20Sopenharmony_ci */ 56358c2ecf20Sopenharmony_ci } 56368c2ecf20Sopenharmony_ci 56378c2ecf20Sopenharmony_ci end_err = devlink_fmsg_binary_pair_nest_end(fmsg); 56388c2ecf20Sopenharmony_ci if (end_err) 56398c2ecf20Sopenharmony_ci err = end_err; 56408c2ecf20Sopenharmony_ci 56418c2ecf20Sopenharmony_ci return err; 56428c2ecf20Sopenharmony_ci} 56438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put); 56448c2ecf20Sopenharmony_ci 56458c2ecf20Sopenharmony_cistatic int 56468c2ecf20Sopenharmony_cidevlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb) 56478c2ecf20Sopenharmony_ci{ 56488c2ecf20Sopenharmony_ci switch (msg->nla_type) { 56498c2ecf20Sopenharmony_ci case NLA_FLAG: 56508c2ecf20Sopenharmony_ci case NLA_U8: 56518c2ecf20Sopenharmony_ci case NLA_U32: 56528c2ecf20Sopenharmony_ci case NLA_U64: 56538c2ecf20Sopenharmony_ci case NLA_NUL_STRING: 56548c2ecf20Sopenharmony_ci case NLA_BINARY: 56558c2ecf20Sopenharmony_ci return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE, 56568c2ecf20Sopenharmony_ci msg->nla_type); 56578c2ecf20Sopenharmony_ci default: 56588c2ecf20Sopenharmony_ci return -EINVAL; 56598c2ecf20Sopenharmony_ci } 56608c2ecf20Sopenharmony_ci} 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_cistatic int 56638c2ecf20Sopenharmony_cidevlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb) 56648c2ecf20Sopenharmony_ci{ 56658c2ecf20Sopenharmony_ci int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA; 56668c2ecf20Sopenharmony_ci u8 tmp; 56678c2ecf20Sopenharmony_ci 56688c2ecf20Sopenharmony_ci switch (msg->nla_type) { 56698c2ecf20Sopenharmony_ci case NLA_FLAG: 56708c2ecf20Sopenharmony_ci /* Always provide flag data, regardless of its value */ 56718c2ecf20Sopenharmony_ci tmp = *(bool *) msg->value; 56728c2ecf20Sopenharmony_ci 56738c2ecf20Sopenharmony_ci return nla_put_u8(skb, attrtype, tmp); 56748c2ecf20Sopenharmony_ci case NLA_U8: 56758c2ecf20Sopenharmony_ci return nla_put_u8(skb, attrtype, *(u8 *) msg->value); 56768c2ecf20Sopenharmony_ci case NLA_U32: 56778c2ecf20Sopenharmony_ci return nla_put_u32(skb, attrtype, *(u32 *) msg->value); 56788c2ecf20Sopenharmony_ci case NLA_U64: 56798c2ecf20Sopenharmony_ci return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value, 56808c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD); 56818c2ecf20Sopenharmony_ci case NLA_NUL_STRING: 56828c2ecf20Sopenharmony_ci return nla_put_string(skb, attrtype, (char *) &msg->value); 56838c2ecf20Sopenharmony_ci case NLA_BINARY: 56848c2ecf20Sopenharmony_ci return nla_put(skb, attrtype, msg->len, (void *) &msg->value); 56858c2ecf20Sopenharmony_ci default: 56868c2ecf20Sopenharmony_ci return -EINVAL; 56878c2ecf20Sopenharmony_ci } 56888c2ecf20Sopenharmony_ci} 56898c2ecf20Sopenharmony_ci 56908c2ecf20Sopenharmony_cistatic int 56918c2ecf20Sopenharmony_cidevlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb, 56928c2ecf20Sopenharmony_ci int *start) 56938c2ecf20Sopenharmony_ci{ 56948c2ecf20Sopenharmony_ci struct devlink_fmsg_item *item; 56958c2ecf20Sopenharmony_ci struct nlattr *fmsg_nlattr; 56968c2ecf20Sopenharmony_ci int i = 0; 56978c2ecf20Sopenharmony_ci int err; 56988c2ecf20Sopenharmony_ci 56998c2ecf20Sopenharmony_ci fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG); 57008c2ecf20Sopenharmony_ci if (!fmsg_nlattr) 57018c2ecf20Sopenharmony_ci return -EMSGSIZE; 57028c2ecf20Sopenharmony_ci 57038c2ecf20Sopenharmony_ci list_for_each_entry(item, &fmsg->item_list, list) { 57048c2ecf20Sopenharmony_ci if (i < *start) { 57058c2ecf20Sopenharmony_ci i++; 57068c2ecf20Sopenharmony_ci continue; 57078c2ecf20Sopenharmony_ci } 57088c2ecf20Sopenharmony_ci 57098c2ecf20Sopenharmony_ci switch (item->attrtype) { 57108c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_OBJ_NEST_START: 57118c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_PAIR_NEST_START: 57128c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_ARR_NEST_START: 57138c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_NEST_END: 57148c2ecf20Sopenharmony_ci err = nla_put_flag(skb, item->attrtype); 57158c2ecf20Sopenharmony_ci break; 57168c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA: 57178c2ecf20Sopenharmony_ci err = devlink_fmsg_item_fill_type(item, skb); 57188c2ecf20Sopenharmony_ci if (err) 57198c2ecf20Sopenharmony_ci break; 57208c2ecf20Sopenharmony_ci err = devlink_fmsg_item_fill_data(item, skb); 57218c2ecf20Sopenharmony_ci break; 57228c2ecf20Sopenharmony_ci case DEVLINK_ATTR_FMSG_OBJ_NAME: 57238c2ecf20Sopenharmony_ci err = nla_put_string(skb, item->attrtype, 57248c2ecf20Sopenharmony_ci (char *) &item->value); 57258c2ecf20Sopenharmony_ci break; 57268c2ecf20Sopenharmony_ci default: 57278c2ecf20Sopenharmony_ci err = -EINVAL; 57288c2ecf20Sopenharmony_ci break; 57298c2ecf20Sopenharmony_ci } 57308c2ecf20Sopenharmony_ci if (!err) 57318c2ecf20Sopenharmony_ci *start = ++i; 57328c2ecf20Sopenharmony_ci else 57338c2ecf20Sopenharmony_ci break; 57348c2ecf20Sopenharmony_ci } 57358c2ecf20Sopenharmony_ci 57368c2ecf20Sopenharmony_ci nla_nest_end(skb, fmsg_nlattr); 57378c2ecf20Sopenharmony_ci return err; 57388c2ecf20Sopenharmony_ci} 57398c2ecf20Sopenharmony_ci 57408c2ecf20Sopenharmony_cistatic int devlink_fmsg_snd(struct devlink_fmsg *fmsg, 57418c2ecf20Sopenharmony_ci struct genl_info *info, 57428c2ecf20Sopenharmony_ci enum devlink_command cmd, int flags) 57438c2ecf20Sopenharmony_ci{ 57448c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 57458c2ecf20Sopenharmony_ci struct sk_buff *skb; 57468c2ecf20Sopenharmony_ci bool last = false; 57478c2ecf20Sopenharmony_ci int index = 0; 57488c2ecf20Sopenharmony_ci void *hdr; 57498c2ecf20Sopenharmony_ci int err; 57508c2ecf20Sopenharmony_ci 57518c2ecf20Sopenharmony_ci while (!last) { 57528c2ecf20Sopenharmony_ci int tmp_index = index; 57538c2ecf20Sopenharmony_ci 57548c2ecf20Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 57558c2ecf20Sopenharmony_ci if (!skb) 57568c2ecf20Sopenharmony_ci return -ENOMEM; 57578c2ecf20Sopenharmony_ci 57588c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 57598c2ecf20Sopenharmony_ci &devlink_nl_family, flags | NLM_F_MULTI, cmd); 57608c2ecf20Sopenharmony_ci if (!hdr) { 57618c2ecf20Sopenharmony_ci err = -EMSGSIZE; 57628c2ecf20Sopenharmony_ci goto nla_put_failure; 57638c2ecf20Sopenharmony_ci } 57648c2ecf20Sopenharmony_ci 57658c2ecf20Sopenharmony_ci err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 57668c2ecf20Sopenharmony_ci if (!err) 57678c2ecf20Sopenharmony_ci last = true; 57688c2ecf20Sopenharmony_ci else if (err != -EMSGSIZE || tmp_index == index) 57698c2ecf20Sopenharmony_ci goto nla_put_failure; 57708c2ecf20Sopenharmony_ci 57718c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 57728c2ecf20Sopenharmony_ci err = genlmsg_reply(skb, info); 57738c2ecf20Sopenharmony_ci if (err) 57748c2ecf20Sopenharmony_ci return err; 57758c2ecf20Sopenharmony_ci } 57768c2ecf20Sopenharmony_ci 57778c2ecf20Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 57788c2ecf20Sopenharmony_ci if (!skb) 57798c2ecf20Sopenharmony_ci return -ENOMEM; 57808c2ecf20Sopenharmony_ci nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 57818c2ecf20Sopenharmony_ci NLMSG_DONE, 0, flags | NLM_F_MULTI); 57828c2ecf20Sopenharmony_ci if (!nlh) { 57838c2ecf20Sopenharmony_ci err = -EMSGSIZE; 57848c2ecf20Sopenharmony_ci goto nla_put_failure; 57858c2ecf20Sopenharmony_ci } 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci return genlmsg_reply(skb, info); 57888c2ecf20Sopenharmony_ci 57898c2ecf20Sopenharmony_cinla_put_failure: 57908c2ecf20Sopenharmony_ci nlmsg_free(skb); 57918c2ecf20Sopenharmony_ci return err; 57928c2ecf20Sopenharmony_ci} 57938c2ecf20Sopenharmony_ci 57948c2ecf20Sopenharmony_cistatic int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb, 57958c2ecf20Sopenharmony_ci struct netlink_callback *cb, 57968c2ecf20Sopenharmony_ci enum devlink_command cmd) 57978c2ecf20Sopenharmony_ci{ 57988c2ecf20Sopenharmony_ci int index = cb->args[0]; 57998c2ecf20Sopenharmony_ci int tmp_index = index; 58008c2ecf20Sopenharmony_ci void *hdr; 58018c2ecf20Sopenharmony_ci int err; 58028c2ecf20Sopenharmony_ci 58038c2ecf20Sopenharmony_ci hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 58048c2ecf20Sopenharmony_ci &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd); 58058c2ecf20Sopenharmony_ci if (!hdr) { 58068c2ecf20Sopenharmony_ci err = -EMSGSIZE; 58078c2ecf20Sopenharmony_ci goto nla_put_failure; 58088c2ecf20Sopenharmony_ci } 58098c2ecf20Sopenharmony_ci 58108c2ecf20Sopenharmony_ci err = devlink_fmsg_prepare_skb(fmsg, skb, &index); 58118c2ecf20Sopenharmony_ci if ((err && err != -EMSGSIZE) || tmp_index == index) 58128c2ecf20Sopenharmony_ci goto nla_put_failure; 58138c2ecf20Sopenharmony_ci 58148c2ecf20Sopenharmony_ci cb->args[0] = index; 58158c2ecf20Sopenharmony_ci genlmsg_end(skb, hdr); 58168c2ecf20Sopenharmony_ci return skb->len; 58178c2ecf20Sopenharmony_ci 58188c2ecf20Sopenharmony_cinla_put_failure: 58198c2ecf20Sopenharmony_ci genlmsg_cancel(skb, hdr); 58208c2ecf20Sopenharmony_ci return err; 58218c2ecf20Sopenharmony_ci} 58228c2ecf20Sopenharmony_ci 58238c2ecf20Sopenharmony_cistruct devlink_health_reporter { 58248c2ecf20Sopenharmony_ci struct list_head list; 58258c2ecf20Sopenharmony_ci void *priv; 58268c2ecf20Sopenharmony_ci const struct devlink_health_reporter_ops *ops; 58278c2ecf20Sopenharmony_ci struct devlink *devlink; 58288c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 58298c2ecf20Sopenharmony_ci struct devlink_fmsg *dump_fmsg; 58308c2ecf20Sopenharmony_ci struct mutex dump_lock; /* lock parallel read/write from dump buffers */ 58318c2ecf20Sopenharmony_ci u64 graceful_period; 58328c2ecf20Sopenharmony_ci bool auto_recover; 58338c2ecf20Sopenharmony_ci bool auto_dump; 58348c2ecf20Sopenharmony_ci u8 health_state; 58358c2ecf20Sopenharmony_ci u64 dump_ts; 58368c2ecf20Sopenharmony_ci u64 dump_real_ts; 58378c2ecf20Sopenharmony_ci u64 error_count; 58388c2ecf20Sopenharmony_ci u64 recovery_count; 58398c2ecf20Sopenharmony_ci u64 last_recovery_ts; 58408c2ecf20Sopenharmony_ci refcount_t refcount; 58418c2ecf20Sopenharmony_ci}; 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_civoid * 58448c2ecf20Sopenharmony_cidevlink_health_reporter_priv(struct devlink_health_reporter *reporter) 58458c2ecf20Sopenharmony_ci{ 58468c2ecf20Sopenharmony_ci return reporter->priv; 58478c2ecf20Sopenharmony_ci} 58488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_priv); 58498c2ecf20Sopenharmony_ci 58508c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 58518c2ecf20Sopenharmony_ci__devlink_health_reporter_find_by_name(struct list_head *reporter_list, 58528c2ecf20Sopenharmony_ci struct mutex *list_lock, 58538c2ecf20Sopenharmony_ci const char *reporter_name) 58548c2ecf20Sopenharmony_ci{ 58558c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci lockdep_assert_held(list_lock); 58588c2ecf20Sopenharmony_ci list_for_each_entry(reporter, reporter_list, list) 58598c2ecf20Sopenharmony_ci if (!strcmp(reporter->ops->name, reporter_name)) 58608c2ecf20Sopenharmony_ci return reporter; 58618c2ecf20Sopenharmony_ci return NULL; 58628c2ecf20Sopenharmony_ci} 58638c2ecf20Sopenharmony_ci 58648c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 58658c2ecf20Sopenharmony_cidevlink_health_reporter_find_by_name(struct devlink *devlink, 58668c2ecf20Sopenharmony_ci const char *reporter_name) 58678c2ecf20Sopenharmony_ci{ 58688c2ecf20Sopenharmony_ci return __devlink_health_reporter_find_by_name(&devlink->reporter_list, 58698c2ecf20Sopenharmony_ci &devlink->reporters_lock, 58708c2ecf20Sopenharmony_ci reporter_name); 58718c2ecf20Sopenharmony_ci} 58728c2ecf20Sopenharmony_ci 58738c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 58748c2ecf20Sopenharmony_cidevlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port, 58758c2ecf20Sopenharmony_ci const char *reporter_name) 58768c2ecf20Sopenharmony_ci{ 58778c2ecf20Sopenharmony_ci return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list, 58788c2ecf20Sopenharmony_ci &devlink_port->reporters_lock, 58798c2ecf20Sopenharmony_ci reporter_name); 58808c2ecf20Sopenharmony_ci} 58818c2ecf20Sopenharmony_ci 58828c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 58838c2ecf20Sopenharmony_ci__devlink_health_reporter_create(struct devlink *devlink, 58848c2ecf20Sopenharmony_ci const struct devlink_health_reporter_ops *ops, 58858c2ecf20Sopenharmony_ci u64 graceful_period, void *priv) 58868c2ecf20Sopenharmony_ci{ 58878c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 58888c2ecf20Sopenharmony_ci 58898c2ecf20Sopenharmony_ci if (WARN_ON(graceful_period && !ops->recover)) 58908c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 58918c2ecf20Sopenharmony_ci 58928c2ecf20Sopenharmony_ci reporter = kzalloc(sizeof(*reporter), GFP_KERNEL); 58938c2ecf20Sopenharmony_ci if (!reporter) 58948c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 58958c2ecf20Sopenharmony_ci 58968c2ecf20Sopenharmony_ci reporter->priv = priv; 58978c2ecf20Sopenharmony_ci reporter->ops = ops; 58988c2ecf20Sopenharmony_ci reporter->devlink = devlink; 58998c2ecf20Sopenharmony_ci reporter->graceful_period = graceful_period; 59008c2ecf20Sopenharmony_ci reporter->auto_recover = !!ops->recover; 59018c2ecf20Sopenharmony_ci reporter->auto_dump = !!ops->dump; 59028c2ecf20Sopenharmony_ci mutex_init(&reporter->dump_lock); 59038c2ecf20Sopenharmony_ci refcount_set(&reporter->refcount, 1); 59048c2ecf20Sopenharmony_ci return reporter; 59058c2ecf20Sopenharmony_ci} 59068c2ecf20Sopenharmony_ci 59078c2ecf20Sopenharmony_ci/** 59088c2ecf20Sopenharmony_ci * devlink_port_health_reporter_create - create devlink health reporter for 59098c2ecf20Sopenharmony_ci * specified port instance 59108c2ecf20Sopenharmony_ci * 59118c2ecf20Sopenharmony_ci * @port: devlink_port which should contain the new reporter 59128c2ecf20Sopenharmony_ci * @ops: ops 59138c2ecf20Sopenharmony_ci * @graceful_period: to avoid recovery loops, in msecs 59148c2ecf20Sopenharmony_ci * @priv: priv 59158c2ecf20Sopenharmony_ci */ 59168c2ecf20Sopenharmony_cistruct devlink_health_reporter * 59178c2ecf20Sopenharmony_cidevlink_port_health_reporter_create(struct devlink_port *port, 59188c2ecf20Sopenharmony_ci const struct devlink_health_reporter_ops *ops, 59198c2ecf20Sopenharmony_ci u64 graceful_period, void *priv) 59208c2ecf20Sopenharmony_ci{ 59218c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 59228c2ecf20Sopenharmony_ci 59238c2ecf20Sopenharmony_ci mutex_lock(&port->reporters_lock); 59248c2ecf20Sopenharmony_ci if (__devlink_health_reporter_find_by_name(&port->reporter_list, 59258c2ecf20Sopenharmony_ci &port->reporters_lock, ops->name)) { 59268c2ecf20Sopenharmony_ci reporter = ERR_PTR(-EEXIST); 59278c2ecf20Sopenharmony_ci goto unlock; 59288c2ecf20Sopenharmony_ci } 59298c2ecf20Sopenharmony_ci 59308c2ecf20Sopenharmony_ci reporter = __devlink_health_reporter_create(port->devlink, ops, 59318c2ecf20Sopenharmony_ci graceful_period, priv); 59328c2ecf20Sopenharmony_ci if (IS_ERR(reporter)) 59338c2ecf20Sopenharmony_ci goto unlock; 59348c2ecf20Sopenharmony_ci 59358c2ecf20Sopenharmony_ci reporter->devlink_port = port; 59368c2ecf20Sopenharmony_ci list_add_tail(&reporter->list, &port->reporter_list); 59378c2ecf20Sopenharmony_ciunlock: 59388c2ecf20Sopenharmony_ci mutex_unlock(&port->reporters_lock); 59398c2ecf20Sopenharmony_ci return reporter; 59408c2ecf20Sopenharmony_ci} 59418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_health_reporter_create); 59428c2ecf20Sopenharmony_ci 59438c2ecf20Sopenharmony_ci/** 59448c2ecf20Sopenharmony_ci * devlink_health_reporter_create - create devlink health reporter 59458c2ecf20Sopenharmony_ci * 59468c2ecf20Sopenharmony_ci * @devlink: devlink 59478c2ecf20Sopenharmony_ci * @ops: ops 59488c2ecf20Sopenharmony_ci * @graceful_period: to avoid recovery loops, in msecs 59498c2ecf20Sopenharmony_ci * @priv: priv 59508c2ecf20Sopenharmony_ci */ 59518c2ecf20Sopenharmony_cistruct devlink_health_reporter * 59528c2ecf20Sopenharmony_cidevlink_health_reporter_create(struct devlink *devlink, 59538c2ecf20Sopenharmony_ci const struct devlink_health_reporter_ops *ops, 59548c2ecf20Sopenharmony_ci u64 graceful_period, void *priv) 59558c2ecf20Sopenharmony_ci{ 59568c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 59578c2ecf20Sopenharmony_ci 59588c2ecf20Sopenharmony_ci mutex_lock(&devlink->reporters_lock); 59598c2ecf20Sopenharmony_ci if (devlink_health_reporter_find_by_name(devlink, ops->name)) { 59608c2ecf20Sopenharmony_ci reporter = ERR_PTR(-EEXIST); 59618c2ecf20Sopenharmony_ci goto unlock; 59628c2ecf20Sopenharmony_ci } 59638c2ecf20Sopenharmony_ci 59648c2ecf20Sopenharmony_ci reporter = __devlink_health_reporter_create(devlink, ops, 59658c2ecf20Sopenharmony_ci graceful_period, priv); 59668c2ecf20Sopenharmony_ci if (IS_ERR(reporter)) 59678c2ecf20Sopenharmony_ci goto unlock; 59688c2ecf20Sopenharmony_ci 59698c2ecf20Sopenharmony_ci list_add_tail(&reporter->list, &devlink->reporter_list); 59708c2ecf20Sopenharmony_ciunlock: 59718c2ecf20Sopenharmony_ci mutex_unlock(&devlink->reporters_lock); 59728c2ecf20Sopenharmony_ci return reporter; 59738c2ecf20Sopenharmony_ci} 59748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_create); 59758c2ecf20Sopenharmony_ci 59768c2ecf20Sopenharmony_cistatic void 59778c2ecf20Sopenharmony_cidevlink_health_reporter_free(struct devlink_health_reporter *reporter) 59788c2ecf20Sopenharmony_ci{ 59798c2ecf20Sopenharmony_ci mutex_destroy(&reporter->dump_lock); 59808c2ecf20Sopenharmony_ci if (reporter->dump_fmsg) 59818c2ecf20Sopenharmony_ci devlink_fmsg_free(reporter->dump_fmsg); 59828c2ecf20Sopenharmony_ci kfree(reporter); 59838c2ecf20Sopenharmony_ci} 59848c2ecf20Sopenharmony_ci 59858c2ecf20Sopenharmony_cistatic void 59868c2ecf20Sopenharmony_cidevlink_health_reporter_put(struct devlink_health_reporter *reporter) 59878c2ecf20Sopenharmony_ci{ 59888c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&reporter->refcount)) 59898c2ecf20Sopenharmony_ci devlink_health_reporter_free(reporter); 59908c2ecf20Sopenharmony_ci} 59918c2ecf20Sopenharmony_ci 59928c2ecf20Sopenharmony_cistatic void 59938c2ecf20Sopenharmony_ci__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter) 59948c2ecf20Sopenharmony_ci{ 59958c2ecf20Sopenharmony_ci list_del(&reporter->list); 59968c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 59978c2ecf20Sopenharmony_ci} 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ci/** 60008c2ecf20Sopenharmony_ci * devlink_health_reporter_destroy - destroy devlink health reporter 60018c2ecf20Sopenharmony_ci * 60028c2ecf20Sopenharmony_ci * @reporter: devlink health reporter to destroy 60038c2ecf20Sopenharmony_ci */ 60048c2ecf20Sopenharmony_civoid 60058c2ecf20Sopenharmony_cidevlink_health_reporter_destroy(struct devlink_health_reporter *reporter) 60068c2ecf20Sopenharmony_ci{ 60078c2ecf20Sopenharmony_ci struct mutex *lock = &reporter->devlink->reporters_lock; 60088c2ecf20Sopenharmony_ci 60098c2ecf20Sopenharmony_ci mutex_lock(lock); 60108c2ecf20Sopenharmony_ci __devlink_health_reporter_destroy(reporter); 60118c2ecf20Sopenharmony_ci mutex_unlock(lock); 60128c2ecf20Sopenharmony_ci} 60138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_destroy); 60148c2ecf20Sopenharmony_ci 60158c2ecf20Sopenharmony_ci/** 60168c2ecf20Sopenharmony_ci * devlink_port_health_reporter_destroy - destroy devlink port health reporter 60178c2ecf20Sopenharmony_ci * 60188c2ecf20Sopenharmony_ci * @reporter: devlink health reporter to destroy 60198c2ecf20Sopenharmony_ci */ 60208c2ecf20Sopenharmony_civoid 60218c2ecf20Sopenharmony_cidevlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter) 60228c2ecf20Sopenharmony_ci{ 60238c2ecf20Sopenharmony_ci struct mutex *lock = &reporter->devlink_port->reporters_lock; 60248c2ecf20Sopenharmony_ci 60258c2ecf20Sopenharmony_ci mutex_lock(lock); 60268c2ecf20Sopenharmony_ci __devlink_health_reporter_destroy(reporter); 60278c2ecf20Sopenharmony_ci mutex_unlock(lock); 60288c2ecf20Sopenharmony_ci} 60298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy); 60308c2ecf20Sopenharmony_ci 60318c2ecf20Sopenharmony_cistatic int 60328c2ecf20Sopenharmony_cidevlink_nl_health_reporter_fill(struct sk_buff *msg, 60338c2ecf20Sopenharmony_ci struct devlink *devlink, 60348c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter, 60358c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, 60368c2ecf20Sopenharmony_ci u32 seq, int flags) 60378c2ecf20Sopenharmony_ci{ 60388c2ecf20Sopenharmony_ci struct nlattr *reporter_attr; 60398c2ecf20Sopenharmony_ci void *hdr; 60408c2ecf20Sopenharmony_ci 60418c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 60428c2ecf20Sopenharmony_ci if (!hdr) 60438c2ecf20Sopenharmony_ci return -EMSGSIZE; 60448c2ecf20Sopenharmony_ci 60458c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 60468c2ecf20Sopenharmony_ci goto genlmsg_cancel; 60478c2ecf20Sopenharmony_ci 60488c2ecf20Sopenharmony_ci if (reporter->devlink_port) { 60498c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index)) 60508c2ecf20Sopenharmony_ci goto genlmsg_cancel; 60518c2ecf20Sopenharmony_ci } 60528c2ecf20Sopenharmony_ci reporter_attr = nla_nest_start_noflag(msg, 60538c2ecf20Sopenharmony_ci DEVLINK_ATTR_HEALTH_REPORTER); 60548c2ecf20Sopenharmony_ci if (!reporter_attr) 60558c2ecf20Sopenharmony_ci goto genlmsg_cancel; 60568c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME, 60578c2ecf20Sopenharmony_ci reporter->ops->name)) 60588c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60598c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE, 60608c2ecf20Sopenharmony_ci reporter->health_state)) 60618c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60628c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT, 60638c2ecf20Sopenharmony_ci reporter->error_count, DEVLINK_ATTR_PAD)) 60648c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60658c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT, 60668c2ecf20Sopenharmony_ci reporter->recovery_count, DEVLINK_ATTR_PAD)) 60678c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60688c2ecf20Sopenharmony_ci if (reporter->ops->recover && 60698c2ecf20Sopenharmony_ci nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, 60708c2ecf20Sopenharmony_ci reporter->graceful_period, 60718c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 60728c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60738c2ecf20Sopenharmony_ci if (reporter->ops->recover && 60748c2ecf20Sopenharmony_ci nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, 60758c2ecf20Sopenharmony_ci reporter->auto_recover)) 60768c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60778c2ecf20Sopenharmony_ci if (reporter->dump_fmsg && 60788c2ecf20Sopenharmony_ci nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS, 60798c2ecf20Sopenharmony_ci jiffies_to_msecs(reporter->dump_ts), 60808c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 60818c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60828c2ecf20Sopenharmony_ci if (reporter->dump_fmsg && 60838c2ecf20Sopenharmony_ci nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS, 60848c2ecf20Sopenharmony_ci reporter->dump_real_ts, DEVLINK_ATTR_PAD)) 60858c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60868c2ecf20Sopenharmony_ci if (reporter->ops->dump && 60878c2ecf20Sopenharmony_ci nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP, 60888c2ecf20Sopenharmony_ci reporter->auto_dump)) 60898c2ecf20Sopenharmony_ci goto reporter_nest_cancel; 60908c2ecf20Sopenharmony_ci 60918c2ecf20Sopenharmony_ci nla_nest_end(msg, reporter_attr); 60928c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 60938c2ecf20Sopenharmony_ci return 0; 60948c2ecf20Sopenharmony_ci 60958c2ecf20Sopenharmony_cireporter_nest_cancel: 60968c2ecf20Sopenharmony_ci nla_nest_end(msg, reporter_attr); 60978c2ecf20Sopenharmony_cigenlmsg_cancel: 60988c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 60998c2ecf20Sopenharmony_ci return -EMSGSIZE; 61008c2ecf20Sopenharmony_ci} 61018c2ecf20Sopenharmony_ci 61028c2ecf20Sopenharmony_cistatic void devlink_recover_notify(struct devlink_health_reporter *reporter, 61038c2ecf20Sopenharmony_ci enum devlink_command cmd) 61048c2ecf20Sopenharmony_ci{ 61058c2ecf20Sopenharmony_ci struct sk_buff *msg; 61068c2ecf20Sopenharmony_ci int err; 61078c2ecf20Sopenharmony_ci 61088c2ecf20Sopenharmony_ci WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 61098c2ecf20Sopenharmony_ci 61108c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 61118c2ecf20Sopenharmony_ci if (!msg) 61128c2ecf20Sopenharmony_ci return; 61138c2ecf20Sopenharmony_ci 61148c2ecf20Sopenharmony_ci err = devlink_nl_health_reporter_fill(msg, reporter->devlink, 61158c2ecf20Sopenharmony_ci reporter, cmd, 0, 0, 0); 61168c2ecf20Sopenharmony_ci if (err) { 61178c2ecf20Sopenharmony_ci nlmsg_free(msg); 61188c2ecf20Sopenharmony_ci return; 61198c2ecf20Sopenharmony_ci } 61208c2ecf20Sopenharmony_ci 61218c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, 61228c2ecf20Sopenharmony_ci devlink_net(reporter->devlink), 61238c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 61248c2ecf20Sopenharmony_ci} 61258c2ecf20Sopenharmony_ci 61268c2ecf20Sopenharmony_civoid 61278c2ecf20Sopenharmony_cidevlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter) 61288c2ecf20Sopenharmony_ci{ 61298c2ecf20Sopenharmony_ci reporter->recovery_count++; 61308c2ecf20Sopenharmony_ci reporter->last_recovery_ts = jiffies; 61318c2ecf20Sopenharmony_ci} 61328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done); 61338c2ecf20Sopenharmony_ci 61348c2ecf20Sopenharmony_cistatic int 61358c2ecf20Sopenharmony_cidevlink_health_reporter_recover(struct devlink_health_reporter *reporter, 61368c2ecf20Sopenharmony_ci void *priv_ctx, struct netlink_ext_ack *extack) 61378c2ecf20Sopenharmony_ci{ 61388c2ecf20Sopenharmony_ci int err; 61398c2ecf20Sopenharmony_ci 61408c2ecf20Sopenharmony_ci if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY) 61418c2ecf20Sopenharmony_ci return 0; 61428c2ecf20Sopenharmony_ci 61438c2ecf20Sopenharmony_ci if (!reporter->ops->recover) 61448c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 61458c2ecf20Sopenharmony_ci 61468c2ecf20Sopenharmony_ci err = reporter->ops->recover(reporter, priv_ctx, extack); 61478c2ecf20Sopenharmony_ci if (err) 61488c2ecf20Sopenharmony_ci return err; 61498c2ecf20Sopenharmony_ci 61508c2ecf20Sopenharmony_ci devlink_health_reporter_recovery_done(reporter); 61518c2ecf20Sopenharmony_ci reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY; 61528c2ecf20Sopenharmony_ci devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 61538c2ecf20Sopenharmony_ci 61548c2ecf20Sopenharmony_ci return 0; 61558c2ecf20Sopenharmony_ci} 61568c2ecf20Sopenharmony_ci 61578c2ecf20Sopenharmony_cistatic void 61588c2ecf20Sopenharmony_cidevlink_health_dump_clear(struct devlink_health_reporter *reporter) 61598c2ecf20Sopenharmony_ci{ 61608c2ecf20Sopenharmony_ci if (!reporter->dump_fmsg) 61618c2ecf20Sopenharmony_ci return; 61628c2ecf20Sopenharmony_ci devlink_fmsg_free(reporter->dump_fmsg); 61638c2ecf20Sopenharmony_ci reporter->dump_fmsg = NULL; 61648c2ecf20Sopenharmony_ci} 61658c2ecf20Sopenharmony_ci 61668c2ecf20Sopenharmony_cistatic int devlink_health_do_dump(struct devlink_health_reporter *reporter, 61678c2ecf20Sopenharmony_ci void *priv_ctx, 61688c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 61698c2ecf20Sopenharmony_ci{ 61708c2ecf20Sopenharmony_ci int err; 61718c2ecf20Sopenharmony_ci 61728c2ecf20Sopenharmony_ci if (!reporter->ops->dump) 61738c2ecf20Sopenharmony_ci return 0; 61748c2ecf20Sopenharmony_ci 61758c2ecf20Sopenharmony_ci if (reporter->dump_fmsg) 61768c2ecf20Sopenharmony_ci return 0; 61778c2ecf20Sopenharmony_ci 61788c2ecf20Sopenharmony_ci reporter->dump_fmsg = devlink_fmsg_alloc(); 61798c2ecf20Sopenharmony_ci if (!reporter->dump_fmsg) { 61808c2ecf20Sopenharmony_ci err = -ENOMEM; 61818c2ecf20Sopenharmony_ci return err; 61828c2ecf20Sopenharmony_ci } 61838c2ecf20Sopenharmony_ci 61848c2ecf20Sopenharmony_ci err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg); 61858c2ecf20Sopenharmony_ci if (err) 61868c2ecf20Sopenharmony_ci goto dump_err; 61878c2ecf20Sopenharmony_ci 61888c2ecf20Sopenharmony_ci err = reporter->ops->dump(reporter, reporter->dump_fmsg, 61898c2ecf20Sopenharmony_ci priv_ctx, extack); 61908c2ecf20Sopenharmony_ci if (err) 61918c2ecf20Sopenharmony_ci goto dump_err; 61928c2ecf20Sopenharmony_ci 61938c2ecf20Sopenharmony_ci err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg); 61948c2ecf20Sopenharmony_ci if (err) 61958c2ecf20Sopenharmony_ci goto dump_err; 61968c2ecf20Sopenharmony_ci 61978c2ecf20Sopenharmony_ci reporter->dump_ts = jiffies; 61988c2ecf20Sopenharmony_ci reporter->dump_real_ts = ktime_get_real_ns(); 61998c2ecf20Sopenharmony_ci 62008c2ecf20Sopenharmony_ci return 0; 62018c2ecf20Sopenharmony_ci 62028c2ecf20Sopenharmony_cidump_err: 62038c2ecf20Sopenharmony_ci devlink_health_dump_clear(reporter); 62048c2ecf20Sopenharmony_ci return err; 62058c2ecf20Sopenharmony_ci} 62068c2ecf20Sopenharmony_ci 62078c2ecf20Sopenharmony_ciint devlink_health_report(struct devlink_health_reporter *reporter, 62088c2ecf20Sopenharmony_ci const char *msg, void *priv_ctx) 62098c2ecf20Sopenharmony_ci{ 62108c2ecf20Sopenharmony_ci enum devlink_health_reporter_state prev_health_state; 62118c2ecf20Sopenharmony_ci struct devlink *devlink = reporter->devlink; 62128c2ecf20Sopenharmony_ci unsigned long recover_ts_threshold; 62138c2ecf20Sopenharmony_ci 62148c2ecf20Sopenharmony_ci /* write a log message of the current error */ 62158c2ecf20Sopenharmony_ci WARN_ON(!msg); 62168c2ecf20Sopenharmony_ci trace_devlink_health_report(devlink, reporter->ops->name, msg); 62178c2ecf20Sopenharmony_ci reporter->error_count++; 62188c2ecf20Sopenharmony_ci prev_health_state = reporter->health_state; 62198c2ecf20Sopenharmony_ci reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; 62208c2ecf20Sopenharmony_ci devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 62218c2ecf20Sopenharmony_ci 62228c2ecf20Sopenharmony_ci /* abort if the previous error wasn't recovered */ 62238c2ecf20Sopenharmony_ci recover_ts_threshold = reporter->last_recovery_ts + 62248c2ecf20Sopenharmony_ci msecs_to_jiffies(reporter->graceful_period); 62258c2ecf20Sopenharmony_ci if (reporter->auto_recover && 62268c2ecf20Sopenharmony_ci (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY || 62278c2ecf20Sopenharmony_ci (reporter->last_recovery_ts && reporter->recovery_count && 62288c2ecf20Sopenharmony_ci time_is_after_jiffies(recover_ts_threshold)))) { 62298c2ecf20Sopenharmony_ci trace_devlink_health_recover_aborted(devlink, 62308c2ecf20Sopenharmony_ci reporter->ops->name, 62318c2ecf20Sopenharmony_ci reporter->health_state, 62328c2ecf20Sopenharmony_ci jiffies - 62338c2ecf20Sopenharmony_ci reporter->last_recovery_ts); 62348c2ecf20Sopenharmony_ci return -ECANCELED; 62358c2ecf20Sopenharmony_ci } 62368c2ecf20Sopenharmony_ci 62378c2ecf20Sopenharmony_ci reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; 62388c2ecf20Sopenharmony_ci 62398c2ecf20Sopenharmony_ci if (reporter->auto_dump) { 62408c2ecf20Sopenharmony_ci mutex_lock(&reporter->dump_lock); 62418c2ecf20Sopenharmony_ci /* store current dump of current error, for later analysis */ 62428c2ecf20Sopenharmony_ci devlink_health_do_dump(reporter, priv_ctx, NULL); 62438c2ecf20Sopenharmony_ci mutex_unlock(&reporter->dump_lock); 62448c2ecf20Sopenharmony_ci } 62458c2ecf20Sopenharmony_ci 62468c2ecf20Sopenharmony_ci if (reporter->auto_recover) 62478c2ecf20Sopenharmony_ci return devlink_health_reporter_recover(reporter, 62488c2ecf20Sopenharmony_ci priv_ctx, NULL); 62498c2ecf20Sopenharmony_ci 62508c2ecf20Sopenharmony_ci return 0; 62518c2ecf20Sopenharmony_ci} 62528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_report); 62538c2ecf20Sopenharmony_ci 62548c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 62558c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_attrs(struct devlink *devlink, 62568c2ecf20Sopenharmony_ci struct nlattr **attrs) 62578c2ecf20Sopenharmony_ci{ 62588c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 62598c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 62608c2ecf20Sopenharmony_ci char *reporter_name; 62618c2ecf20Sopenharmony_ci 62628c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]) 62638c2ecf20Sopenharmony_ci return NULL; 62648c2ecf20Sopenharmony_ci 62658c2ecf20Sopenharmony_ci reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]); 62668c2ecf20Sopenharmony_ci devlink_port = devlink_port_get_from_attrs(devlink, attrs); 62678c2ecf20Sopenharmony_ci if (IS_ERR(devlink_port)) { 62688c2ecf20Sopenharmony_ci mutex_lock(&devlink->reporters_lock); 62698c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_find_by_name(devlink, reporter_name); 62708c2ecf20Sopenharmony_ci if (reporter) 62718c2ecf20Sopenharmony_ci refcount_inc(&reporter->refcount); 62728c2ecf20Sopenharmony_ci mutex_unlock(&devlink->reporters_lock); 62738c2ecf20Sopenharmony_ci } else { 62748c2ecf20Sopenharmony_ci mutex_lock(&devlink_port->reporters_lock); 62758c2ecf20Sopenharmony_ci reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name); 62768c2ecf20Sopenharmony_ci if (reporter) 62778c2ecf20Sopenharmony_ci refcount_inc(&reporter->refcount); 62788c2ecf20Sopenharmony_ci mutex_unlock(&devlink_port->reporters_lock); 62798c2ecf20Sopenharmony_ci } 62808c2ecf20Sopenharmony_ci 62818c2ecf20Sopenharmony_ci return reporter; 62828c2ecf20Sopenharmony_ci} 62838c2ecf20Sopenharmony_ci 62848c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 62858c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_info(struct devlink *devlink, 62868c2ecf20Sopenharmony_ci struct genl_info *info) 62878c2ecf20Sopenharmony_ci{ 62888c2ecf20Sopenharmony_ci return devlink_health_reporter_get_from_attrs(devlink, info->attrs); 62898c2ecf20Sopenharmony_ci} 62908c2ecf20Sopenharmony_ci 62918c2ecf20Sopenharmony_cistatic struct devlink_health_reporter * 62928c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_cb(struct netlink_callback *cb) 62938c2ecf20Sopenharmony_ci{ 62948c2ecf20Sopenharmony_ci const struct genl_dumpit_info *info = genl_dumpit_info(cb); 62958c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 62968c2ecf20Sopenharmony_ci struct nlattr **attrs = info->attrs; 62978c2ecf20Sopenharmony_ci struct devlink *devlink; 62988c2ecf20Sopenharmony_ci 62998c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 63008c2ecf20Sopenharmony_ci devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs); 63018c2ecf20Sopenharmony_ci if (IS_ERR(devlink)) 63028c2ecf20Sopenharmony_ci goto unlock; 63038c2ecf20Sopenharmony_ci 63048c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_attrs(devlink, attrs); 63058c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 63068c2ecf20Sopenharmony_ci return reporter; 63078c2ecf20Sopenharmony_ciunlock: 63088c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 63098c2ecf20Sopenharmony_ci return NULL; 63108c2ecf20Sopenharmony_ci} 63118c2ecf20Sopenharmony_ci 63128c2ecf20Sopenharmony_civoid 63138c2ecf20Sopenharmony_cidevlink_health_reporter_state_update(struct devlink_health_reporter *reporter, 63148c2ecf20Sopenharmony_ci enum devlink_health_reporter_state state) 63158c2ecf20Sopenharmony_ci{ 63168c2ecf20Sopenharmony_ci if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY && 63178c2ecf20Sopenharmony_ci state != DEVLINK_HEALTH_REPORTER_STATE_ERROR)) 63188c2ecf20Sopenharmony_ci return; 63198c2ecf20Sopenharmony_ci 63208c2ecf20Sopenharmony_ci if (reporter->health_state == state) 63218c2ecf20Sopenharmony_ci return; 63228c2ecf20Sopenharmony_ci 63238c2ecf20Sopenharmony_ci reporter->health_state = state; 63248c2ecf20Sopenharmony_ci trace_devlink_health_reporter_state_update(reporter->devlink, 63258c2ecf20Sopenharmony_ci reporter->ops->name, state); 63268c2ecf20Sopenharmony_ci devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER); 63278c2ecf20Sopenharmony_ci} 63288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_state_update); 63298c2ecf20Sopenharmony_ci 63308c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb, 63318c2ecf20Sopenharmony_ci struct genl_info *info) 63328c2ecf20Sopenharmony_ci{ 63338c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 63348c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 63358c2ecf20Sopenharmony_ci struct sk_buff *msg; 63368c2ecf20Sopenharmony_ci int err; 63378c2ecf20Sopenharmony_ci 63388c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 63398c2ecf20Sopenharmony_ci if (!reporter) 63408c2ecf20Sopenharmony_ci return -EINVAL; 63418c2ecf20Sopenharmony_ci 63428c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 63438c2ecf20Sopenharmony_ci if (!msg) { 63448c2ecf20Sopenharmony_ci err = -ENOMEM; 63458c2ecf20Sopenharmony_ci goto out; 63468c2ecf20Sopenharmony_ci } 63478c2ecf20Sopenharmony_ci 63488c2ecf20Sopenharmony_ci err = devlink_nl_health_reporter_fill(msg, devlink, reporter, 63498c2ecf20Sopenharmony_ci DEVLINK_CMD_HEALTH_REPORTER_GET, 63508c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 63518c2ecf20Sopenharmony_ci 0); 63528c2ecf20Sopenharmony_ci if (err) { 63538c2ecf20Sopenharmony_ci nlmsg_free(msg); 63548c2ecf20Sopenharmony_ci goto out; 63558c2ecf20Sopenharmony_ci } 63568c2ecf20Sopenharmony_ci 63578c2ecf20Sopenharmony_ci err = genlmsg_reply(msg, info); 63588c2ecf20Sopenharmony_ciout: 63598c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 63608c2ecf20Sopenharmony_ci return err; 63618c2ecf20Sopenharmony_ci} 63628c2ecf20Sopenharmony_ci 63638c2ecf20Sopenharmony_cistatic int 63648c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg, 63658c2ecf20Sopenharmony_ci struct netlink_callback *cb) 63668c2ecf20Sopenharmony_ci{ 63678c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 63688c2ecf20Sopenharmony_ci struct devlink_port *port; 63698c2ecf20Sopenharmony_ci struct devlink *devlink; 63708c2ecf20Sopenharmony_ci int start = cb->args[0]; 63718c2ecf20Sopenharmony_ci int idx = 0; 63728c2ecf20Sopenharmony_ci int err; 63738c2ecf20Sopenharmony_ci 63748c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 63758c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 63768c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 63778c2ecf20Sopenharmony_ci continue; 63788c2ecf20Sopenharmony_ci mutex_lock(&devlink->reporters_lock); 63798c2ecf20Sopenharmony_ci list_for_each_entry(reporter, &devlink->reporter_list, 63808c2ecf20Sopenharmony_ci list) { 63818c2ecf20Sopenharmony_ci if (idx < start) { 63828c2ecf20Sopenharmony_ci idx++; 63838c2ecf20Sopenharmony_ci continue; 63848c2ecf20Sopenharmony_ci } 63858c2ecf20Sopenharmony_ci err = devlink_nl_health_reporter_fill(msg, devlink, 63868c2ecf20Sopenharmony_ci reporter, 63878c2ecf20Sopenharmony_ci DEVLINK_CMD_HEALTH_REPORTER_GET, 63888c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 63898c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 63908c2ecf20Sopenharmony_ci NLM_F_MULTI); 63918c2ecf20Sopenharmony_ci if (err) { 63928c2ecf20Sopenharmony_ci mutex_unlock(&devlink->reporters_lock); 63938c2ecf20Sopenharmony_ci goto out; 63948c2ecf20Sopenharmony_ci } 63958c2ecf20Sopenharmony_ci idx++; 63968c2ecf20Sopenharmony_ci } 63978c2ecf20Sopenharmony_ci mutex_unlock(&devlink->reporters_lock); 63988c2ecf20Sopenharmony_ci } 63998c2ecf20Sopenharmony_ci 64008c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 64018c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 64028c2ecf20Sopenharmony_ci continue; 64038c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 64048c2ecf20Sopenharmony_ci list_for_each_entry(port, &devlink->port_list, list) { 64058c2ecf20Sopenharmony_ci mutex_lock(&port->reporters_lock); 64068c2ecf20Sopenharmony_ci list_for_each_entry(reporter, &port->reporter_list, list) { 64078c2ecf20Sopenharmony_ci if (idx < start) { 64088c2ecf20Sopenharmony_ci idx++; 64098c2ecf20Sopenharmony_ci continue; 64108c2ecf20Sopenharmony_ci } 64118c2ecf20Sopenharmony_ci err = devlink_nl_health_reporter_fill(msg, devlink, reporter, 64128c2ecf20Sopenharmony_ci DEVLINK_CMD_HEALTH_REPORTER_GET, 64138c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 64148c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 64158c2ecf20Sopenharmony_ci NLM_F_MULTI); 64168c2ecf20Sopenharmony_ci if (err) { 64178c2ecf20Sopenharmony_ci mutex_unlock(&port->reporters_lock); 64188c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 64198c2ecf20Sopenharmony_ci goto out; 64208c2ecf20Sopenharmony_ci } 64218c2ecf20Sopenharmony_ci idx++; 64228c2ecf20Sopenharmony_ci } 64238c2ecf20Sopenharmony_ci mutex_unlock(&port->reporters_lock); 64248c2ecf20Sopenharmony_ci } 64258c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 64268c2ecf20Sopenharmony_ci } 64278c2ecf20Sopenharmony_ciout: 64288c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 64298c2ecf20Sopenharmony_ci 64308c2ecf20Sopenharmony_ci cb->args[0] = idx; 64318c2ecf20Sopenharmony_ci return msg->len; 64328c2ecf20Sopenharmony_ci} 64338c2ecf20Sopenharmony_ci 64348c2ecf20Sopenharmony_cistatic int 64358c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb, 64368c2ecf20Sopenharmony_ci struct genl_info *info) 64378c2ecf20Sopenharmony_ci{ 64388c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 64398c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 64408c2ecf20Sopenharmony_ci int err; 64418c2ecf20Sopenharmony_ci 64428c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 64438c2ecf20Sopenharmony_ci if (!reporter) 64448c2ecf20Sopenharmony_ci return -EINVAL; 64458c2ecf20Sopenharmony_ci 64468c2ecf20Sopenharmony_ci if (!reporter->ops->recover && 64478c2ecf20Sopenharmony_ci (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] || 64488c2ecf20Sopenharmony_ci info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) { 64498c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 64508c2ecf20Sopenharmony_ci goto out; 64518c2ecf20Sopenharmony_ci } 64528c2ecf20Sopenharmony_ci if (!reporter->ops->dump && 64538c2ecf20Sopenharmony_ci info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) { 64548c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 64558c2ecf20Sopenharmony_ci goto out; 64568c2ecf20Sopenharmony_ci } 64578c2ecf20Sopenharmony_ci 64588c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) 64598c2ecf20Sopenharmony_ci reporter->graceful_period = 64608c2ecf20Sopenharmony_ci nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]); 64618c2ecf20Sopenharmony_ci 64628c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]) 64638c2ecf20Sopenharmony_ci reporter->auto_recover = 64648c2ecf20Sopenharmony_ci nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]); 64658c2ecf20Sopenharmony_ci 64668c2ecf20Sopenharmony_ci if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) 64678c2ecf20Sopenharmony_ci reporter->auto_dump = 64688c2ecf20Sopenharmony_ci nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]); 64698c2ecf20Sopenharmony_ci 64708c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 64718c2ecf20Sopenharmony_ci return 0; 64728c2ecf20Sopenharmony_ciout: 64738c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 64748c2ecf20Sopenharmony_ci return err; 64758c2ecf20Sopenharmony_ci} 64768c2ecf20Sopenharmony_ci 64778c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb, 64788c2ecf20Sopenharmony_ci struct genl_info *info) 64798c2ecf20Sopenharmony_ci{ 64808c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 64818c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 64828c2ecf20Sopenharmony_ci int err; 64838c2ecf20Sopenharmony_ci 64848c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 64858c2ecf20Sopenharmony_ci if (!reporter) 64868c2ecf20Sopenharmony_ci return -EINVAL; 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_ci err = devlink_health_reporter_recover(reporter, NULL, info->extack); 64898c2ecf20Sopenharmony_ci 64908c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 64918c2ecf20Sopenharmony_ci return err; 64928c2ecf20Sopenharmony_ci} 64938c2ecf20Sopenharmony_ci 64948c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb, 64958c2ecf20Sopenharmony_ci struct genl_info *info) 64968c2ecf20Sopenharmony_ci{ 64978c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 64988c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 64998c2ecf20Sopenharmony_ci struct devlink_fmsg *fmsg; 65008c2ecf20Sopenharmony_ci int err; 65018c2ecf20Sopenharmony_ci 65028c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 65038c2ecf20Sopenharmony_ci if (!reporter) 65048c2ecf20Sopenharmony_ci return -EINVAL; 65058c2ecf20Sopenharmony_ci 65068c2ecf20Sopenharmony_ci if (!reporter->ops->diagnose) { 65078c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 65098c2ecf20Sopenharmony_ci } 65108c2ecf20Sopenharmony_ci 65118c2ecf20Sopenharmony_ci fmsg = devlink_fmsg_alloc(); 65128c2ecf20Sopenharmony_ci if (!fmsg) { 65138c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65148c2ecf20Sopenharmony_ci return -ENOMEM; 65158c2ecf20Sopenharmony_ci } 65168c2ecf20Sopenharmony_ci 65178c2ecf20Sopenharmony_ci err = devlink_fmsg_obj_nest_start(fmsg); 65188c2ecf20Sopenharmony_ci if (err) 65198c2ecf20Sopenharmony_ci goto out; 65208c2ecf20Sopenharmony_ci 65218c2ecf20Sopenharmony_ci err = reporter->ops->diagnose(reporter, fmsg, info->extack); 65228c2ecf20Sopenharmony_ci if (err) 65238c2ecf20Sopenharmony_ci goto out; 65248c2ecf20Sopenharmony_ci 65258c2ecf20Sopenharmony_ci err = devlink_fmsg_obj_nest_end(fmsg); 65268c2ecf20Sopenharmony_ci if (err) 65278c2ecf20Sopenharmony_ci goto out; 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci err = devlink_fmsg_snd(fmsg, info, 65308c2ecf20Sopenharmony_ci DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0); 65318c2ecf20Sopenharmony_ci 65328c2ecf20Sopenharmony_ciout: 65338c2ecf20Sopenharmony_ci devlink_fmsg_free(fmsg); 65348c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65358c2ecf20Sopenharmony_ci return err; 65368c2ecf20Sopenharmony_ci} 65378c2ecf20Sopenharmony_ci 65388c2ecf20Sopenharmony_cistatic int 65398c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb, 65408c2ecf20Sopenharmony_ci struct netlink_callback *cb) 65418c2ecf20Sopenharmony_ci{ 65428c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 65438c2ecf20Sopenharmony_ci u64 start = cb->args[0]; 65448c2ecf20Sopenharmony_ci int err; 65458c2ecf20Sopenharmony_ci 65468c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_cb(cb); 65478c2ecf20Sopenharmony_ci if (!reporter) 65488c2ecf20Sopenharmony_ci return -EINVAL; 65498c2ecf20Sopenharmony_ci 65508c2ecf20Sopenharmony_ci if (!reporter->ops->dump) { 65518c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 65528c2ecf20Sopenharmony_ci goto out; 65538c2ecf20Sopenharmony_ci } 65548c2ecf20Sopenharmony_ci mutex_lock(&reporter->dump_lock); 65558c2ecf20Sopenharmony_ci if (!start) { 65568c2ecf20Sopenharmony_ci err = devlink_health_do_dump(reporter, NULL, cb->extack); 65578c2ecf20Sopenharmony_ci if (err) 65588c2ecf20Sopenharmony_ci goto unlock; 65598c2ecf20Sopenharmony_ci cb->args[1] = reporter->dump_ts; 65608c2ecf20Sopenharmony_ci } 65618c2ecf20Sopenharmony_ci if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) { 65628c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry"); 65638c2ecf20Sopenharmony_ci err = -EAGAIN; 65648c2ecf20Sopenharmony_ci goto unlock; 65658c2ecf20Sopenharmony_ci } 65668c2ecf20Sopenharmony_ci 65678c2ecf20Sopenharmony_ci err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb, 65688c2ecf20Sopenharmony_ci DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET); 65698c2ecf20Sopenharmony_ciunlock: 65708c2ecf20Sopenharmony_ci mutex_unlock(&reporter->dump_lock); 65718c2ecf20Sopenharmony_ciout: 65728c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65738c2ecf20Sopenharmony_ci return err; 65748c2ecf20Sopenharmony_ci} 65758c2ecf20Sopenharmony_ci 65768c2ecf20Sopenharmony_cistatic int 65778c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb, 65788c2ecf20Sopenharmony_ci struct genl_info *info) 65798c2ecf20Sopenharmony_ci{ 65808c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 65818c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 65828c2ecf20Sopenharmony_ci 65838c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 65848c2ecf20Sopenharmony_ci if (!reporter) 65858c2ecf20Sopenharmony_ci return -EINVAL; 65868c2ecf20Sopenharmony_ci 65878c2ecf20Sopenharmony_ci if (!reporter->ops->dump) { 65888c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 65908c2ecf20Sopenharmony_ci } 65918c2ecf20Sopenharmony_ci 65928c2ecf20Sopenharmony_ci mutex_lock(&reporter->dump_lock); 65938c2ecf20Sopenharmony_ci devlink_health_dump_clear(reporter); 65948c2ecf20Sopenharmony_ci mutex_unlock(&reporter->dump_lock); 65958c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 65968c2ecf20Sopenharmony_ci return 0; 65978c2ecf20Sopenharmony_ci} 65988c2ecf20Sopenharmony_ci 65998c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb, 66008c2ecf20Sopenharmony_ci struct genl_info *info) 66018c2ecf20Sopenharmony_ci{ 66028c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 66038c2ecf20Sopenharmony_ci struct devlink_health_reporter *reporter; 66048c2ecf20Sopenharmony_ci int err; 66058c2ecf20Sopenharmony_ci 66068c2ecf20Sopenharmony_ci reporter = devlink_health_reporter_get_from_info(devlink, info); 66078c2ecf20Sopenharmony_ci if (!reporter) 66088c2ecf20Sopenharmony_ci return -EINVAL; 66098c2ecf20Sopenharmony_ci 66108c2ecf20Sopenharmony_ci if (!reporter->ops->test) { 66118c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 66128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 66138c2ecf20Sopenharmony_ci } 66148c2ecf20Sopenharmony_ci 66158c2ecf20Sopenharmony_ci err = reporter->ops->test(reporter, info->extack); 66168c2ecf20Sopenharmony_ci 66178c2ecf20Sopenharmony_ci devlink_health_reporter_put(reporter); 66188c2ecf20Sopenharmony_ci return err; 66198c2ecf20Sopenharmony_ci} 66208c2ecf20Sopenharmony_ci 66218c2ecf20Sopenharmony_cistruct devlink_stats { 66228c2ecf20Sopenharmony_ci u64 rx_bytes; 66238c2ecf20Sopenharmony_ci u64 rx_packets; 66248c2ecf20Sopenharmony_ci struct u64_stats_sync syncp; 66258c2ecf20Sopenharmony_ci}; 66268c2ecf20Sopenharmony_ci 66278c2ecf20Sopenharmony_ci/** 66288c2ecf20Sopenharmony_ci * struct devlink_trap_policer_item - Packet trap policer attributes. 66298c2ecf20Sopenharmony_ci * @policer: Immutable packet trap policer attributes. 66308c2ecf20Sopenharmony_ci * @rate: Rate in packets / sec. 66318c2ecf20Sopenharmony_ci * @burst: Burst size in packets. 66328c2ecf20Sopenharmony_ci * @list: trap_policer_list member. 66338c2ecf20Sopenharmony_ci * 66348c2ecf20Sopenharmony_ci * Describes packet trap policer attributes. Created by devlink during trap 66358c2ecf20Sopenharmony_ci * policer registration. 66368c2ecf20Sopenharmony_ci */ 66378c2ecf20Sopenharmony_cistruct devlink_trap_policer_item { 66388c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer; 66398c2ecf20Sopenharmony_ci u64 rate; 66408c2ecf20Sopenharmony_ci u64 burst; 66418c2ecf20Sopenharmony_ci struct list_head list; 66428c2ecf20Sopenharmony_ci}; 66438c2ecf20Sopenharmony_ci 66448c2ecf20Sopenharmony_ci/** 66458c2ecf20Sopenharmony_ci * struct devlink_trap_group_item - Packet trap group attributes. 66468c2ecf20Sopenharmony_ci * @group: Immutable packet trap group attributes. 66478c2ecf20Sopenharmony_ci * @policer_item: Associated policer item. Can be NULL. 66488c2ecf20Sopenharmony_ci * @list: trap_group_list member. 66498c2ecf20Sopenharmony_ci * @stats: Trap group statistics. 66508c2ecf20Sopenharmony_ci * 66518c2ecf20Sopenharmony_ci * Describes packet trap group attributes. Created by devlink during trap 66528c2ecf20Sopenharmony_ci * group registration. 66538c2ecf20Sopenharmony_ci */ 66548c2ecf20Sopenharmony_cistruct devlink_trap_group_item { 66558c2ecf20Sopenharmony_ci const struct devlink_trap_group *group; 66568c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 66578c2ecf20Sopenharmony_ci struct list_head list; 66588c2ecf20Sopenharmony_ci struct devlink_stats __percpu *stats; 66598c2ecf20Sopenharmony_ci}; 66608c2ecf20Sopenharmony_ci 66618c2ecf20Sopenharmony_ci/** 66628c2ecf20Sopenharmony_ci * struct devlink_trap_item - Packet trap attributes. 66638c2ecf20Sopenharmony_ci * @trap: Immutable packet trap attributes. 66648c2ecf20Sopenharmony_ci * @group_item: Associated group item. 66658c2ecf20Sopenharmony_ci * @list: trap_list member. 66668c2ecf20Sopenharmony_ci * @action: Trap action. 66678c2ecf20Sopenharmony_ci * @stats: Trap statistics. 66688c2ecf20Sopenharmony_ci * @priv: Driver private information. 66698c2ecf20Sopenharmony_ci * 66708c2ecf20Sopenharmony_ci * Describes both mutable and immutable packet trap attributes. Created by 66718c2ecf20Sopenharmony_ci * devlink during trap registration and used for all trap related operations. 66728c2ecf20Sopenharmony_ci */ 66738c2ecf20Sopenharmony_cistruct devlink_trap_item { 66748c2ecf20Sopenharmony_ci const struct devlink_trap *trap; 66758c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 66768c2ecf20Sopenharmony_ci struct list_head list; 66778c2ecf20Sopenharmony_ci enum devlink_trap_action action; 66788c2ecf20Sopenharmony_ci struct devlink_stats __percpu *stats; 66798c2ecf20Sopenharmony_ci void *priv; 66808c2ecf20Sopenharmony_ci}; 66818c2ecf20Sopenharmony_ci 66828c2ecf20Sopenharmony_cistatic struct devlink_trap_policer_item * 66838c2ecf20Sopenharmony_cidevlink_trap_policer_item_lookup(struct devlink *devlink, u32 id) 66848c2ecf20Sopenharmony_ci{ 66858c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 66868c2ecf20Sopenharmony_ci 66878c2ecf20Sopenharmony_ci list_for_each_entry(policer_item, &devlink->trap_policer_list, list) { 66888c2ecf20Sopenharmony_ci if (policer_item->policer->id == id) 66898c2ecf20Sopenharmony_ci return policer_item; 66908c2ecf20Sopenharmony_ci } 66918c2ecf20Sopenharmony_ci 66928c2ecf20Sopenharmony_ci return NULL; 66938c2ecf20Sopenharmony_ci} 66948c2ecf20Sopenharmony_ci 66958c2ecf20Sopenharmony_cistatic struct devlink_trap_item * 66968c2ecf20Sopenharmony_cidevlink_trap_item_lookup(struct devlink *devlink, const char *name) 66978c2ecf20Sopenharmony_ci{ 66988c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 66998c2ecf20Sopenharmony_ci 67008c2ecf20Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 67018c2ecf20Sopenharmony_ci if (!strcmp(trap_item->trap->name, name)) 67028c2ecf20Sopenharmony_ci return trap_item; 67038c2ecf20Sopenharmony_ci } 67048c2ecf20Sopenharmony_ci 67058c2ecf20Sopenharmony_ci return NULL; 67068c2ecf20Sopenharmony_ci} 67078c2ecf20Sopenharmony_ci 67088c2ecf20Sopenharmony_cistatic struct devlink_trap_item * 67098c2ecf20Sopenharmony_cidevlink_trap_item_get_from_info(struct devlink *devlink, 67108c2ecf20Sopenharmony_ci struct genl_info *info) 67118c2ecf20Sopenharmony_ci{ 67128c2ecf20Sopenharmony_ci struct nlattr *attr; 67138c2ecf20Sopenharmony_ci 67148c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_NAME]) 67158c2ecf20Sopenharmony_ci return NULL; 67168c2ecf20Sopenharmony_ci attr = info->attrs[DEVLINK_ATTR_TRAP_NAME]; 67178c2ecf20Sopenharmony_ci 67188c2ecf20Sopenharmony_ci return devlink_trap_item_lookup(devlink, nla_data(attr)); 67198c2ecf20Sopenharmony_ci} 67208c2ecf20Sopenharmony_ci 67218c2ecf20Sopenharmony_cistatic int 67228c2ecf20Sopenharmony_cidevlink_trap_action_get_from_info(struct genl_info *info, 67238c2ecf20Sopenharmony_ci enum devlink_trap_action *p_trap_action) 67248c2ecf20Sopenharmony_ci{ 67258c2ecf20Sopenharmony_ci u8 val; 67268c2ecf20Sopenharmony_ci 67278c2ecf20Sopenharmony_ci val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]); 67288c2ecf20Sopenharmony_ci switch (val) { 67298c2ecf20Sopenharmony_ci case DEVLINK_TRAP_ACTION_DROP: 67308c2ecf20Sopenharmony_ci case DEVLINK_TRAP_ACTION_TRAP: 67318c2ecf20Sopenharmony_ci case DEVLINK_TRAP_ACTION_MIRROR: 67328c2ecf20Sopenharmony_ci *p_trap_action = val; 67338c2ecf20Sopenharmony_ci break; 67348c2ecf20Sopenharmony_ci default: 67358c2ecf20Sopenharmony_ci return -EINVAL; 67368c2ecf20Sopenharmony_ci } 67378c2ecf20Sopenharmony_ci 67388c2ecf20Sopenharmony_ci return 0; 67398c2ecf20Sopenharmony_ci} 67408c2ecf20Sopenharmony_ci 67418c2ecf20Sopenharmony_cistatic int devlink_trap_metadata_put(struct sk_buff *msg, 67428c2ecf20Sopenharmony_ci const struct devlink_trap *trap) 67438c2ecf20Sopenharmony_ci{ 67448c2ecf20Sopenharmony_ci struct nlattr *attr; 67458c2ecf20Sopenharmony_ci 67468c2ecf20Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA); 67478c2ecf20Sopenharmony_ci if (!attr) 67488c2ecf20Sopenharmony_ci return -EMSGSIZE; 67498c2ecf20Sopenharmony_ci 67508c2ecf20Sopenharmony_ci if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) && 67518c2ecf20Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT)) 67528c2ecf20Sopenharmony_ci goto nla_put_failure; 67538c2ecf20Sopenharmony_ci if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) && 67548c2ecf20Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE)) 67558c2ecf20Sopenharmony_ci goto nla_put_failure; 67568c2ecf20Sopenharmony_ci 67578c2ecf20Sopenharmony_ci nla_nest_end(msg, attr); 67588c2ecf20Sopenharmony_ci 67598c2ecf20Sopenharmony_ci return 0; 67608c2ecf20Sopenharmony_ci 67618c2ecf20Sopenharmony_cinla_put_failure: 67628c2ecf20Sopenharmony_ci nla_nest_cancel(msg, attr); 67638c2ecf20Sopenharmony_ci return -EMSGSIZE; 67648c2ecf20Sopenharmony_ci} 67658c2ecf20Sopenharmony_ci 67668c2ecf20Sopenharmony_cistatic void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats, 67678c2ecf20Sopenharmony_ci struct devlink_stats *stats) 67688c2ecf20Sopenharmony_ci{ 67698c2ecf20Sopenharmony_ci int i; 67708c2ecf20Sopenharmony_ci 67718c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 67728c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 67738c2ecf20Sopenharmony_ci struct devlink_stats *cpu_stats; 67748c2ecf20Sopenharmony_ci u64 rx_packets, rx_bytes; 67758c2ecf20Sopenharmony_ci unsigned int start; 67768c2ecf20Sopenharmony_ci 67778c2ecf20Sopenharmony_ci cpu_stats = per_cpu_ptr(trap_stats, i); 67788c2ecf20Sopenharmony_ci do { 67798c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); 67808c2ecf20Sopenharmony_ci rx_packets = cpu_stats->rx_packets; 67818c2ecf20Sopenharmony_ci rx_bytes = cpu_stats->rx_bytes; 67828c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); 67838c2ecf20Sopenharmony_ci 67848c2ecf20Sopenharmony_ci stats->rx_packets += rx_packets; 67858c2ecf20Sopenharmony_ci stats->rx_bytes += rx_bytes; 67868c2ecf20Sopenharmony_ci } 67878c2ecf20Sopenharmony_ci} 67888c2ecf20Sopenharmony_ci 67898c2ecf20Sopenharmony_cistatic int devlink_trap_stats_put(struct sk_buff *msg, 67908c2ecf20Sopenharmony_ci struct devlink_stats __percpu *trap_stats) 67918c2ecf20Sopenharmony_ci{ 67928c2ecf20Sopenharmony_ci struct devlink_stats stats; 67938c2ecf20Sopenharmony_ci struct nlattr *attr; 67948c2ecf20Sopenharmony_ci 67958c2ecf20Sopenharmony_ci devlink_trap_stats_read(trap_stats, &stats); 67968c2ecf20Sopenharmony_ci 67978c2ecf20Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_STATS); 67988c2ecf20Sopenharmony_ci if (!attr) 67998c2ecf20Sopenharmony_ci return -EMSGSIZE; 68008c2ecf20Sopenharmony_ci 68018c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS, 68028c2ecf20Sopenharmony_ci stats.rx_packets, DEVLINK_ATTR_PAD)) 68038c2ecf20Sopenharmony_ci goto nla_put_failure; 68048c2ecf20Sopenharmony_ci 68058c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES, 68068c2ecf20Sopenharmony_ci stats.rx_bytes, DEVLINK_ATTR_PAD)) 68078c2ecf20Sopenharmony_ci goto nla_put_failure; 68088c2ecf20Sopenharmony_ci 68098c2ecf20Sopenharmony_ci nla_nest_end(msg, attr); 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci return 0; 68128c2ecf20Sopenharmony_ci 68138c2ecf20Sopenharmony_cinla_put_failure: 68148c2ecf20Sopenharmony_ci nla_nest_cancel(msg, attr); 68158c2ecf20Sopenharmony_ci return -EMSGSIZE; 68168c2ecf20Sopenharmony_ci} 68178c2ecf20Sopenharmony_ci 68188c2ecf20Sopenharmony_cistatic int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink, 68198c2ecf20Sopenharmony_ci const struct devlink_trap_item *trap_item, 68208c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 68218c2ecf20Sopenharmony_ci int flags) 68228c2ecf20Sopenharmony_ci{ 68238c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item = trap_item->group_item; 68248c2ecf20Sopenharmony_ci void *hdr; 68258c2ecf20Sopenharmony_ci int err; 68268c2ecf20Sopenharmony_ci 68278c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 68288c2ecf20Sopenharmony_ci if (!hdr) 68298c2ecf20Sopenharmony_ci return -EMSGSIZE; 68308c2ecf20Sopenharmony_ci 68318c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 68328c2ecf20Sopenharmony_ci goto nla_put_failure; 68338c2ecf20Sopenharmony_ci 68348c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME, 68358c2ecf20Sopenharmony_ci group_item->group->name)) 68368c2ecf20Sopenharmony_ci goto nla_put_failure; 68378c2ecf20Sopenharmony_ci 68388c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name)) 68398c2ecf20Sopenharmony_ci goto nla_put_failure; 68408c2ecf20Sopenharmony_ci 68418c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type)) 68428c2ecf20Sopenharmony_ci goto nla_put_failure; 68438c2ecf20Sopenharmony_ci 68448c2ecf20Sopenharmony_ci if (trap_item->trap->generic && 68458c2ecf20Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC)) 68468c2ecf20Sopenharmony_ci goto nla_put_failure; 68478c2ecf20Sopenharmony_ci 68488c2ecf20Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action)) 68498c2ecf20Sopenharmony_ci goto nla_put_failure; 68508c2ecf20Sopenharmony_ci 68518c2ecf20Sopenharmony_ci err = devlink_trap_metadata_put(msg, trap_item->trap); 68528c2ecf20Sopenharmony_ci if (err) 68538c2ecf20Sopenharmony_ci goto nla_put_failure; 68548c2ecf20Sopenharmony_ci 68558c2ecf20Sopenharmony_ci err = devlink_trap_stats_put(msg, trap_item->stats); 68568c2ecf20Sopenharmony_ci if (err) 68578c2ecf20Sopenharmony_ci goto nla_put_failure; 68588c2ecf20Sopenharmony_ci 68598c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 68608c2ecf20Sopenharmony_ci 68618c2ecf20Sopenharmony_ci return 0; 68628c2ecf20Sopenharmony_ci 68638c2ecf20Sopenharmony_cinla_put_failure: 68648c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 68658c2ecf20Sopenharmony_ci return -EMSGSIZE; 68668c2ecf20Sopenharmony_ci} 68678c2ecf20Sopenharmony_ci 68688c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb, 68698c2ecf20Sopenharmony_ci struct genl_info *info) 68708c2ecf20Sopenharmony_ci{ 68718c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 68728c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 68738c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 68748c2ecf20Sopenharmony_ci struct sk_buff *msg; 68758c2ecf20Sopenharmony_ci int err; 68768c2ecf20Sopenharmony_ci 68778c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_list)) 68788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 68798c2ecf20Sopenharmony_ci 68808c2ecf20Sopenharmony_ci trap_item = devlink_trap_item_get_from_info(devlink, info); 68818c2ecf20Sopenharmony_ci if (!trap_item) { 68828c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap"); 68838c2ecf20Sopenharmony_ci return -ENOENT; 68848c2ecf20Sopenharmony_ci } 68858c2ecf20Sopenharmony_ci 68868c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 68878c2ecf20Sopenharmony_ci if (!msg) 68888c2ecf20Sopenharmony_ci return -ENOMEM; 68898c2ecf20Sopenharmony_ci 68908c2ecf20Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, 68918c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_NEW, info->snd_portid, 68928c2ecf20Sopenharmony_ci info->snd_seq, 0); 68938c2ecf20Sopenharmony_ci if (err) 68948c2ecf20Sopenharmony_ci goto err_trap_fill; 68958c2ecf20Sopenharmony_ci 68968c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 68978c2ecf20Sopenharmony_ci 68988c2ecf20Sopenharmony_cierr_trap_fill: 68998c2ecf20Sopenharmony_ci nlmsg_free(msg); 69008c2ecf20Sopenharmony_ci return err; 69018c2ecf20Sopenharmony_ci} 69028c2ecf20Sopenharmony_ci 69038c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg, 69048c2ecf20Sopenharmony_ci struct netlink_callback *cb) 69058c2ecf20Sopenharmony_ci{ 69068c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 69078c2ecf20Sopenharmony_ci struct devlink *devlink; 69088c2ecf20Sopenharmony_ci int start = cb->args[0]; 69098c2ecf20Sopenharmony_ci int idx = 0; 69108c2ecf20Sopenharmony_ci int err; 69118c2ecf20Sopenharmony_ci 69128c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 69138c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 69148c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 69158c2ecf20Sopenharmony_ci continue; 69168c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 69178c2ecf20Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 69188c2ecf20Sopenharmony_ci if (idx < start) { 69198c2ecf20Sopenharmony_ci idx++; 69208c2ecf20Sopenharmony_ci continue; 69218c2ecf20Sopenharmony_ci } 69228c2ecf20Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, 69238c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_NEW, 69248c2ecf20Sopenharmony_ci NETLINK_CB(cb->skb).portid, 69258c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 69268c2ecf20Sopenharmony_ci NLM_F_MULTI); 69278c2ecf20Sopenharmony_ci if (err) { 69288c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 69298c2ecf20Sopenharmony_ci goto out; 69308c2ecf20Sopenharmony_ci } 69318c2ecf20Sopenharmony_ci idx++; 69328c2ecf20Sopenharmony_ci } 69338c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 69348c2ecf20Sopenharmony_ci } 69358c2ecf20Sopenharmony_ciout: 69368c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 69378c2ecf20Sopenharmony_ci 69388c2ecf20Sopenharmony_ci cb->args[0] = idx; 69398c2ecf20Sopenharmony_ci return msg->len; 69408c2ecf20Sopenharmony_ci} 69418c2ecf20Sopenharmony_ci 69428c2ecf20Sopenharmony_cistatic int __devlink_trap_action_set(struct devlink *devlink, 69438c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item, 69448c2ecf20Sopenharmony_ci enum devlink_trap_action trap_action, 69458c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 69468c2ecf20Sopenharmony_ci{ 69478c2ecf20Sopenharmony_ci int err; 69488c2ecf20Sopenharmony_ci 69498c2ecf20Sopenharmony_ci if (trap_item->action != trap_action && 69508c2ecf20Sopenharmony_ci trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) { 69518c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping"); 69528c2ecf20Sopenharmony_ci return 0; 69538c2ecf20Sopenharmony_ci } 69548c2ecf20Sopenharmony_ci 69558c2ecf20Sopenharmony_ci err = devlink->ops->trap_action_set(devlink, trap_item->trap, 69568c2ecf20Sopenharmony_ci trap_action, extack); 69578c2ecf20Sopenharmony_ci if (err) 69588c2ecf20Sopenharmony_ci return err; 69598c2ecf20Sopenharmony_ci 69608c2ecf20Sopenharmony_ci trap_item->action = trap_action; 69618c2ecf20Sopenharmony_ci 69628c2ecf20Sopenharmony_ci return 0; 69638c2ecf20Sopenharmony_ci} 69648c2ecf20Sopenharmony_ci 69658c2ecf20Sopenharmony_cistatic int devlink_trap_action_set(struct devlink *devlink, 69668c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item, 69678c2ecf20Sopenharmony_ci struct genl_info *info) 69688c2ecf20Sopenharmony_ci{ 69698c2ecf20Sopenharmony_ci enum devlink_trap_action trap_action; 69708c2ecf20Sopenharmony_ci int err; 69718c2ecf20Sopenharmony_ci 69728c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION]) 69738c2ecf20Sopenharmony_ci return 0; 69748c2ecf20Sopenharmony_ci 69758c2ecf20Sopenharmony_ci err = devlink_trap_action_get_from_info(info, &trap_action); 69768c2ecf20Sopenharmony_ci if (err) { 69778c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action"); 69788c2ecf20Sopenharmony_ci return -EINVAL; 69798c2ecf20Sopenharmony_ci } 69808c2ecf20Sopenharmony_ci 69818c2ecf20Sopenharmony_ci return __devlink_trap_action_set(devlink, trap_item, trap_action, 69828c2ecf20Sopenharmony_ci info->extack); 69838c2ecf20Sopenharmony_ci} 69848c2ecf20Sopenharmony_ci 69858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb, 69868c2ecf20Sopenharmony_ci struct genl_info *info) 69878c2ecf20Sopenharmony_ci{ 69888c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 69898c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 69908c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 69918c2ecf20Sopenharmony_ci int err; 69928c2ecf20Sopenharmony_ci 69938c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_list)) 69948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 69958c2ecf20Sopenharmony_ci 69968c2ecf20Sopenharmony_ci trap_item = devlink_trap_item_get_from_info(devlink, info); 69978c2ecf20Sopenharmony_ci if (!trap_item) { 69988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap"); 69998c2ecf20Sopenharmony_ci return -ENOENT; 70008c2ecf20Sopenharmony_ci } 70018c2ecf20Sopenharmony_ci 70028c2ecf20Sopenharmony_ci err = devlink_trap_action_set(devlink, trap_item, info); 70038c2ecf20Sopenharmony_ci if (err) 70048c2ecf20Sopenharmony_ci return err; 70058c2ecf20Sopenharmony_ci 70068c2ecf20Sopenharmony_ci return 0; 70078c2ecf20Sopenharmony_ci} 70088c2ecf20Sopenharmony_ci 70098c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item * 70108c2ecf20Sopenharmony_cidevlink_trap_group_item_lookup(struct devlink *devlink, const char *name) 70118c2ecf20Sopenharmony_ci{ 70128c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 70138c2ecf20Sopenharmony_ci 70148c2ecf20Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) { 70158c2ecf20Sopenharmony_ci if (!strcmp(group_item->group->name, name)) 70168c2ecf20Sopenharmony_ci return group_item; 70178c2ecf20Sopenharmony_ci } 70188c2ecf20Sopenharmony_ci 70198c2ecf20Sopenharmony_ci return NULL; 70208c2ecf20Sopenharmony_ci} 70218c2ecf20Sopenharmony_ci 70228c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item * 70238c2ecf20Sopenharmony_cidevlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id) 70248c2ecf20Sopenharmony_ci{ 70258c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 70268c2ecf20Sopenharmony_ci 70278c2ecf20Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) { 70288c2ecf20Sopenharmony_ci if (group_item->group->id == id) 70298c2ecf20Sopenharmony_ci return group_item; 70308c2ecf20Sopenharmony_ci } 70318c2ecf20Sopenharmony_ci 70328c2ecf20Sopenharmony_ci return NULL; 70338c2ecf20Sopenharmony_ci} 70348c2ecf20Sopenharmony_ci 70358c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item * 70368c2ecf20Sopenharmony_cidevlink_trap_group_item_get_from_info(struct devlink *devlink, 70378c2ecf20Sopenharmony_ci struct genl_info *info) 70388c2ecf20Sopenharmony_ci{ 70398c2ecf20Sopenharmony_ci char *name; 70408c2ecf20Sopenharmony_ci 70418c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]) 70428c2ecf20Sopenharmony_ci return NULL; 70438c2ecf20Sopenharmony_ci name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]); 70448c2ecf20Sopenharmony_ci 70458c2ecf20Sopenharmony_ci return devlink_trap_group_item_lookup(devlink, name); 70468c2ecf20Sopenharmony_ci} 70478c2ecf20Sopenharmony_ci 70488c2ecf20Sopenharmony_cistatic int 70498c2ecf20Sopenharmony_cidevlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink, 70508c2ecf20Sopenharmony_ci const struct devlink_trap_group_item *group_item, 70518c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 70528c2ecf20Sopenharmony_ci int flags) 70538c2ecf20Sopenharmony_ci{ 70548c2ecf20Sopenharmony_ci void *hdr; 70558c2ecf20Sopenharmony_ci int err; 70568c2ecf20Sopenharmony_ci 70578c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 70588c2ecf20Sopenharmony_ci if (!hdr) 70598c2ecf20Sopenharmony_ci return -EMSGSIZE; 70608c2ecf20Sopenharmony_ci 70618c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 70628c2ecf20Sopenharmony_ci goto nla_put_failure; 70638c2ecf20Sopenharmony_ci 70648c2ecf20Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME, 70658c2ecf20Sopenharmony_ci group_item->group->name)) 70668c2ecf20Sopenharmony_ci goto nla_put_failure; 70678c2ecf20Sopenharmony_ci 70688c2ecf20Sopenharmony_ci if (group_item->group->generic && 70698c2ecf20Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC)) 70708c2ecf20Sopenharmony_ci goto nla_put_failure; 70718c2ecf20Sopenharmony_ci 70728c2ecf20Sopenharmony_ci if (group_item->policer_item && 70738c2ecf20Sopenharmony_ci nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID, 70748c2ecf20Sopenharmony_ci group_item->policer_item->policer->id)) 70758c2ecf20Sopenharmony_ci goto nla_put_failure; 70768c2ecf20Sopenharmony_ci 70778c2ecf20Sopenharmony_ci err = devlink_trap_stats_put(msg, group_item->stats); 70788c2ecf20Sopenharmony_ci if (err) 70798c2ecf20Sopenharmony_ci goto nla_put_failure; 70808c2ecf20Sopenharmony_ci 70818c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 70828c2ecf20Sopenharmony_ci 70838c2ecf20Sopenharmony_ci return 0; 70848c2ecf20Sopenharmony_ci 70858c2ecf20Sopenharmony_cinla_put_failure: 70868c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 70878c2ecf20Sopenharmony_ci return -EMSGSIZE; 70888c2ecf20Sopenharmony_ci} 70898c2ecf20Sopenharmony_ci 70908c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb, 70918c2ecf20Sopenharmony_ci struct genl_info *info) 70928c2ecf20Sopenharmony_ci{ 70938c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 70948c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 70958c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 70968c2ecf20Sopenharmony_ci struct sk_buff *msg; 70978c2ecf20Sopenharmony_ci int err; 70988c2ecf20Sopenharmony_ci 70998c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_group_list)) 71008c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 71018c2ecf20Sopenharmony_ci 71028c2ecf20Sopenharmony_ci group_item = devlink_trap_group_item_get_from_info(devlink, info); 71038c2ecf20Sopenharmony_ci if (!group_item) { 71048c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group"); 71058c2ecf20Sopenharmony_ci return -ENOENT; 71068c2ecf20Sopenharmony_ci } 71078c2ecf20Sopenharmony_ci 71088c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 71098c2ecf20Sopenharmony_ci if (!msg) 71108c2ecf20Sopenharmony_ci return -ENOMEM; 71118c2ecf20Sopenharmony_ci 71128c2ecf20Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, group_item, 71138c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW, 71148c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 71158c2ecf20Sopenharmony_ci if (err) 71168c2ecf20Sopenharmony_ci goto err_trap_group_fill; 71178c2ecf20Sopenharmony_ci 71188c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 71198c2ecf20Sopenharmony_ci 71208c2ecf20Sopenharmony_cierr_trap_group_fill: 71218c2ecf20Sopenharmony_ci nlmsg_free(msg); 71228c2ecf20Sopenharmony_ci return err; 71238c2ecf20Sopenharmony_ci} 71248c2ecf20Sopenharmony_ci 71258c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg, 71268c2ecf20Sopenharmony_ci struct netlink_callback *cb) 71278c2ecf20Sopenharmony_ci{ 71288c2ecf20Sopenharmony_ci enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW; 71298c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 71308c2ecf20Sopenharmony_ci u32 portid = NETLINK_CB(cb->skb).portid; 71318c2ecf20Sopenharmony_ci struct devlink *devlink; 71328c2ecf20Sopenharmony_ci int start = cb->args[0]; 71338c2ecf20Sopenharmony_ci int idx = 0; 71348c2ecf20Sopenharmony_ci int err; 71358c2ecf20Sopenharmony_ci 71368c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 71378c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 71388c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 71398c2ecf20Sopenharmony_ci continue; 71408c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 71418c2ecf20Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, 71428c2ecf20Sopenharmony_ci list) { 71438c2ecf20Sopenharmony_ci if (idx < start) { 71448c2ecf20Sopenharmony_ci idx++; 71458c2ecf20Sopenharmony_ci continue; 71468c2ecf20Sopenharmony_ci } 71478c2ecf20Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, 71488c2ecf20Sopenharmony_ci group_item, cmd, 71498c2ecf20Sopenharmony_ci portid, 71508c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 71518c2ecf20Sopenharmony_ci NLM_F_MULTI); 71528c2ecf20Sopenharmony_ci if (err) { 71538c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 71548c2ecf20Sopenharmony_ci goto out; 71558c2ecf20Sopenharmony_ci } 71568c2ecf20Sopenharmony_ci idx++; 71578c2ecf20Sopenharmony_ci } 71588c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 71598c2ecf20Sopenharmony_ci } 71608c2ecf20Sopenharmony_ciout: 71618c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 71628c2ecf20Sopenharmony_ci 71638c2ecf20Sopenharmony_ci cb->args[0] = idx; 71648c2ecf20Sopenharmony_ci return msg->len; 71658c2ecf20Sopenharmony_ci} 71668c2ecf20Sopenharmony_ci 71678c2ecf20Sopenharmony_cistatic int 71688c2ecf20Sopenharmony_ci__devlink_trap_group_action_set(struct devlink *devlink, 71698c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item, 71708c2ecf20Sopenharmony_ci enum devlink_trap_action trap_action, 71718c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 71728c2ecf20Sopenharmony_ci{ 71738c2ecf20Sopenharmony_ci const char *group_name = group_item->group->name; 71748c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 71758c2ecf20Sopenharmony_ci int err; 71768c2ecf20Sopenharmony_ci 71778c2ecf20Sopenharmony_ci if (devlink->ops->trap_group_action_set) { 71788c2ecf20Sopenharmony_ci err = devlink->ops->trap_group_action_set(devlink, group_item->group, 71798c2ecf20Sopenharmony_ci trap_action, extack); 71808c2ecf20Sopenharmony_ci if (err) 71818c2ecf20Sopenharmony_ci return err; 71828c2ecf20Sopenharmony_ci 71838c2ecf20Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 71848c2ecf20Sopenharmony_ci if (strcmp(trap_item->group_item->group->name, group_name)) 71858c2ecf20Sopenharmony_ci continue; 71868c2ecf20Sopenharmony_ci if (trap_item->action != trap_action && 71878c2ecf20Sopenharmony_ci trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) 71888c2ecf20Sopenharmony_ci continue; 71898c2ecf20Sopenharmony_ci trap_item->action = trap_action; 71908c2ecf20Sopenharmony_ci } 71918c2ecf20Sopenharmony_ci 71928c2ecf20Sopenharmony_ci return 0; 71938c2ecf20Sopenharmony_ci } 71948c2ecf20Sopenharmony_ci 71958c2ecf20Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 71968c2ecf20Sopenharmony_ci if (strcmp(trap_item->group_item->group->name, group_name)) 71978c2ecf20Sopenharmony_ci continue; 71988c2ecf20Sopenharmony_ci err = __devlink_trap_action_set(devlink, trap_item, 71998c2ecf20Sopenharmony_ci trap_action, extack); 72008c2ecf20Sopenharmony_ci if (err) 72018c2ecf20Sopenharmony_ci return err; 72028c2ecf20Sopenharmony_ci } 72038c2ecf20Sopenharmony_ci 72048c2ecf20Sopenharmony_ci return 0; 72058c2ecf20Sopenharmony_ci} 72068c2ecf20Sopenharmony_ci 72078c2ecf20Sopenharmony_cistatic int 72088c2ecf20Sopenharmony_cidevlink_trap_group_action_set(struct devlink *devlink, 72098c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item, 72108c2ecf20Sopenharmony_ci struct genl_info *info, bool *p_modified) 72118c2ecf20Sopenharmony_ci{ 72128c2ecf20Sopenharmony_ci enum devlink_trap_action trap_action; 72138c2ecf20Sopenharmony_ci int err; 72148c2ecf20Sopenharmony_ci 72158c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION]) 72168c2ecf20Sopenharmony_ci return 0; 72178c2ecf20Sopenharmony_ci 72188c2ecf20Sopenharmony_ci err = devlink_trap_action_get_from_info(info, &trap_action); 72198c2ecf20Sopenharmony_ci if (err) { 72208c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action"); 72218c2ecf20Sopenharmony_ci return -EINVAL; 72228c2ecf20Sopenharmony_ci } 72238c2ecf20Sopenharmony_ci 72248c2ecf20Sopenharmony_ci err = __devlink_trap_group_action_set(devlink, group_item, trap_action, 72258c2ecf20Sopenharmony_ci info->extack); 72268c2ecf20Sopenharmony_ci if (err) 72278c2ecf20Sopenharmony_ci return err; 72288c2ecf20Sopenharmony_ci 72298c2ecf20Sopenharmony_ci *p_modified = true; 72308c2ecf20Sopenharmony_ci 72318c2ecf20Sopenharmony_ci return 0; 72328c2ecf20Sopenharmony_ci} 72338c2ecf20Sopenharmony_ci 72348c2ecf20Sopenharmony_cistatic int devlink_trap_group_set(struct devlink *devlink, 72358c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item, 72368c2ecf20Sopenharmony_ci struct genl_info *info) 72378c2ecf20Sopenharmony_ci{ 72388c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 72398c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 72408c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer; 72418c2ecf20Sopenharmony_ci struct nlattr **attrs = info->attrs; 72428c2ecf20Sopenharmony_ci int err; 72438c2ecf20Sopenharmony_ci 72448c2ecf20Sopenharmony_ci if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) 72458c2ecf20Sopenharmony_ci return 0; 72468c2ecf20Sopenharmony_ci 72478c2ecf20Sopenharmony_ci if (!devlink->ops->trap_group_set) 72488c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 72498c2ecf20Sopenharmony_ci 72508c2ecf20Sopenharmony_ci policer_item = group_item->policer_item; 72518c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) { 72528c2ecf20Sopenharmony_ci u32 policer_id; 72538c2ecf20Sopenharmony_ci 72548c2ecf20Sopenharmony_ci policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]); 72558c2ecf20Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, 72568c2ecf20Sopenharmony_ci policer_id); 72578c2ecf20Sopenharmony_ci if (policer_id && !policer_item) { 72588c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer"); 72598c2ecf20Sopenharmony_ci return -ENOENT; 72608c2ecf20Sopenharmony_ci } 72618c2ecf20Sopenharmony_ci } 72628c2ecf20Sopenharmony_ci policer = policer_item ? policer_item->policer : NULL; 72638c2ecf20Sopenharmony_ci 72648c2ecf20Sopenharmony_ci err = devlink->ops->trap_group_set(devlink, group_item->group, policer, 72658c2ecf20Sopenharmony_ci extack); 72668c2ecf20Sopenharmony_ci if (err) 72678c2ecf20Sopenharmony_ci return err; 72688c2ecf20Sopenharmony_ci 72698c2ecf20Sopenharmony_ci group_item->policer_item = policer_item; 72708c2ecf20Sopenharmony_ci 72718c2ecf20Sopenharmony_ci return 0; 72728c2ecf20Sopenharmony_ci} 72738c2ecf20Sopenharmony_ci 72748c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb, 72758c2ecf20Sopenharmony_ci struct genl_info *info) 72768c2ecf20Sopenharmony_ci{ 72778c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 72788c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 72798c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 72808c2ecf20Sopenharmony_ci bool modified = false; 72818c2ecf20Sopenharmony_ci int err; 72828c2ecf20Sopenharmony_ci 72838c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_group_list)) 72848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 72858c2ecf20Sopenharmony_ci 72868c2ecf20Sopenharmony_ci group_item = devlink_trap_group_item_get_from_info(devlink, info); 72878c2ecf20Sopenharmony_ci if (!group_item) { 72888c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group"); 72898c2ecf20Sopenharmony_ci return -ENOENT; 72908c2ecf20Sopenharmony_ci } 72918c2ecf20Sopenharmony_ci 72928c2ecf20Sopenharmony_ci err = devlink_trap_group_action_set(devlink, group_item, info, 72938c2ecf20Sopenharmony_ci &modified); 72948c2ecf20Sopenharmony_ci if (err) 72958c2ecf20Sopenharmony_ci return err; 72968c2ecf20Sopenharmony_ci 72978c2ecf20Sopenharmony_ci err = devlink_trap_group_set(devlink, group_item, info); 72988c2ecf20Sopenharmony_ci if (err) 72998c2ecf20Sopenharmony_ci goto err_trap_group_set; 73008c2ecf20Sopenharmony_ci 73018c2ecf20Sopenharmony_ci return 0; 73028c2ecf20Sopenharmony_ci 73038c2ecf20Sopenharmony_cierr_trap_group_set: 73048c2ecf20Sopenharmony_ci if (modified) 73058c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already"); 73068c2ecf20Sopenharmony_ci return err; 73078c2ecf20Sopenharmony_ci} 73088c2ecf20Sopenharmony_ci 73098c2ecf20Sopenharmony_cistatic struct devlink_trap_policer_item * 73108c2ecf20Sopenharmony_cidevlink_trap_policer_item_get_from_info(struct devlink *devlink, 73118c2ecf20Sopenharmony_ci struct genl_info *info) 73128c2ecf20Sopenharmony_ci{ 73138c2ecf20Sopenharmony_ci u32 id; 73148c2ecf20Sopenharmony_ci 73158c2ecf20Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) 73168c2ecf20Sopenharmony_ci return NULL; 73178c2ecf20Sopenharmony_ci id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]); 73188c2ecf20Sopenharmony_ci 73198c2ecf20Sopenharmony_ci return devlink_trap_policer_item_lookup(devlink, id); 73208c2ecf20Sopenharmony_ci} 73218c2ecf20Sopenharmony_ci 73228c2ecf20Sopenharmony_cistatic int 73238c2ecf20Sopenharmony_cidevlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink, 73248c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer) 73258c2ecf20Sopenharmony_ci{ 73268c2ecf20Sopenharmony_ci struct nlattr *attr; 73278c2ecf20Sopenharmony_ci u64 drops; 73288c2ecf20Sopenharmony_ci int err; 73298c2ecf20Sopenharmony_ci 73308c2ecf20Sopenharmony_ci if (!devlink->ops->trap_policer_counter_get) 73318c2ecf20Sopenharmony_ci return 0; 73328c2ecf20Sopenharmony_ci 73338c2ecf20Sopenharmony_ci err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops); 73348c2ecf20Sopenharmony_ci if (err) 73358c2ecf20Sopenharmony_ci return err; 73368c2ecf20Sopenharmony_ci 73378c2ecf20Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_STATS); 73388c2ecf20Sopenharmony_ci if (!attr) 73398c2ecf20Sopenharmony_ci return -EMSGSIZE; 73408c2ecf20Sopenharmony_ci 73418c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops, 73428c2ecf20Sopenharmony_ci DEVLINK_ATTR_PAD)) 73438c2ecf20Sopenharmony_ci goto nla_put_failure; 73448c2ecf20Sopenharmony_ci 73458c2ecf20Sopenharmony_ci nla_nest_end(msg, attr); 73468c2ecf20Sopenharmony_ci 73478c2ecf20Sopenharmony_ci return 0; 73488c2ecf20Sopenharmony_ci 73498c2ecf20Sopenharmony_cinla_put_failure: 73508c2ecf20Sopenharmony_ci nla_nest_cancel(msg, attr); 73518c2ecf20Sopenharmony_ci return -EMSGSIZE; 73528c2ecf20Sopenharmony_ci} 73538c2ecf20Sopenharmony_ci 73548c2ecf20Sopenharmony_cistatic int 73558c2ecf20Sopenharmony_cidevlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink, 73568c2ecf20Sopenharmony_ci const struct devlink_trap_policer_item *policer_item, 73578c2ecf20Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 73588c2ecf20Sopenharmony_ci int flags) 73598c2ecf20Sopenharmony_ci{ 73608c2ecf20Sopenharmony_ci void *hdr; 73618c2ecf20Sopenharmony_ci int err; 73628c2ecf20Sopenharmony_ci 73638c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 73648c2ecf20Sopenharmony_ci if (!hdr) 73658c2ecf20Sopenharmony_ci return -EMSGSIZE; 73668c2ecf20Sopenharmony_ci 73678c2ecf20Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 73688c2ecf20Sopenharmony_ci goto nla_put_failure; 73698c2ecf20Sopenharmony_ci 73708c2ecf20Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID, 73718c2ecf20Sopenharmony_ci policer_item->policer->id)) 73728c2ecf20Sopenharmony_ci goto nla_put_failure; 73738c2ecf20Sopenharmony_ci 73748c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE, 73758c2ecf20Sopenharmony_ci policer_item->rate, DEVLINK_ATTR_PAD)) 73768c2ecf20Sopenharmony_ci goto nla_put_failure; 73778c2ecf20Sopenharmony_ci 73788c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST, 73798c2ecf20Sopenharmony_ci policer_item->burst, DEVLINK_ATTR_PAD)) 73808c2ecf20Sopenharmony_ci goto nla_put_failure; 73818c2ecf20Sopenharmony_ci 73828c2ecf20Sopenharmony_ci err = devlink_trap_policer_stats_put(msg, devlink, 73838c2ecf20Sopenharmony_ci policer_item->policer); 73848c2ecf20Sopenharmony_ci if (err) 73858c2ecf20Sopenharmony_ci goto nla_put_failure; 73868c2ecf20Sopenharmony_ci 73878c2ecf20Sopenharmony_ci genlmsg_end(msg, hdr); 73888c2ecf20Sopenharmony_ci 73898c2ecf20Sopenharmony_ci return 0; 73908c2ecf20Sopenharmony_ci 73918c2ecf20Sopenharmony_cinla_put_failure: 73928c2ecf20Sopenharmony_ci genlmsg_cancel(msg, hdr); 73938c2ecf20Sopenharmony_ci return -EMSGSIZE; 73948c2ecf20Sopenharmony_ci} 73958c2ecf20Sopenharmony_ci 73968c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb, 73978c2ecf20Sopenharmony_ci struct genl_info *info) 73988c2ecf20Sopenharmony_ci{ 73998c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 74008c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 74018c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 74028c2ecf20Sopenharmony_ci struct sk_buff *msg; 74038c2ecf20Sopenharmony_ci int err; 74048c2ecf20Sopenharmony_ci 74058c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_policer_list)) 74068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 74078c2ecf20Sopenharmony_ci 74088c2ecf20Sopenharmony_ci policer_item = devlink_trap_policer_item_get_from_info(devlink, info); 74098c2ecf20Sopenharmony_ci if (!policer_item) { 74108c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer"); 74118c2ecf20Sopenharmony_ci return -ENOENT; 74128c2ecf20Sopenharmony_ci } 74138c2ecf20Sopenharmony_ci 74148c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 74158c2ecf20Sopenharmony_ci if (!msg) 74168c2ecf20Sopenharmony_ci return -ENOMEM; 74178c2ecf20Sopenharmony_ci 74188c2ecf20Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, 74198c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW, 74208c2ecf20Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 74218c2ecf20Sopenharmony_ci if (err) 74228c2ecf20Sopenharmony_ci goto err_trap_policer_fill; 74238c2ecf20Sopenharmony_ci 74248c2ecf20Sopenharmony_ci return genlmsg_reply(msg, info); 74258c2ecf20Sopenharmony_ci 74268c2ecf20Sopenharmony_cierr_trap_policer_fill: 74278c2ecf20Sopenharmony_ci nlmsg_free(msg); 74288c2ecf20Sopenharmony_ci return err; 74298c2ecf20Sopenharmony_ci} 74308c2ecf20Sopenharmony_ci 74318c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg, 74328c2ecf20Sopenharmony_ci struct netlink_callback *cb) 74338c2ecf20Sopenharmony_ci{ 74348c2ecf20Sopenharmony_ci enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW; 74358c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 74368c2ecf20Sopenharmony_ci u32 portid = NETLINK_CB(cb->skb).portid; 74378c2ecf20Sopenharmony_ci struct devlink *devlink; 74388c2ecf20Sopenharmony_ci int start = cb->args[0]; 74398c2ecf20Sopenharmony_ci int idx = 0; 74408c2ecf20Sopenharmony_ci int err; 74418c2ecf20Sopenharmony_ci 74428c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 74438c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 74448c2ecf20Sopenharmony_ci if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 74458c2ecf20Sopenharmony_ci continue; 74468c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 74478c2ecf20Sopenharmony_ci list_for_each_entry(policer_item, &devlink->trap_policer_list, 74488c2ecf20Sopenharmony_ci list) { 74498c2ecf20Sopenharmony_ci if (idx < start) { 74508c2ecf20Sopenharmony_ci idx++; 74518c2ecf20Sopenharmony_ci continue; 74528c2ecf20Sopenharmony_ci } 74538c2ecf20Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, 74548c2ecf20Sopenharmony_ci policer_item, cmd, 74558c2ecf20Sopenharmony_ci portid, 74568c2ecf20Sopenharmony_ci cb->nlh->nlmsg_seq, 74578c2ecf20Sopenharmony_ci NLM_F_MULTI); 74588c2ecf20Sopenharmony_ci if (err) { 74598c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 74608c2ecf20Sopenharmony_ci goto out; 74618c2ecf20Sopenharmony_ci } 74628c2ecf20Sopenharmony_ci idx++; 74638c2ecf20Sopenharmony_ci } 74648c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 74658c2ecf20Sopenharmony_ci } 74668c2ecf20Sopenharmony_ciout: 74678c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 74688c2ecf20Sopenharmony_ci 74698c2ecf20Sopenharmony_ci cb->args[0] = idx; 74708c2ecf20Sopenharmony_ci return msg->len; 74718c2ecf20Sopenharmony_ci} 74728c2ecf20Sopenharmony_ci 74738c2ecf20Sopenharmony_cistatic int 74748c2ecf20Sopenharmony_cidevlink_trap_policer_set(struct devlink *devlink, 74758c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item, 74768c2ecf20Sopenharmony_ci struct genl_info *info) 74778c2ecf20Sopenharmony_ci{ 74788c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 74798c2ecf20Sopenharmony_ci struct nlattr **attrs = info->attrs; 74808c2ecf20Sopenharmony_ci u64 rate, burst; 74818c2ecf20Sopenharmony_ci int err; 74828c2ecf20Sopenharmony_ci 74838c2ecf20Sopenharmony_ci rate = policer_item->rate; 74848c2ecf20Sopenharmony_ci burst = policer_item->burst; 74858c2ecf20Sopenharmony_ci 74868c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]) 74878c2ecf20Sopenharmony_ci rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]); 74888c2ecf20Sopenharmony_ci 74898c2ecf20Sopenharmony_ci if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]) 74908c2ecf20Sopenharmony_ci burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]); 74918c2ecf20Sopenharmony_ci 74928c2ecf20Sopenharmony_ci if (rate < policer_item->policer->min_rate) { 74938c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit"); 74948c2ecf20Sopenharmony_ci return -EINVAL; 74958c2ecf20Sopenharmony_ci } 74968c2ecf20Sopenharmony_ci 74978c2ecf20Sopenharmony_ci if (rate > policer_item->policer->max_rate) { 74988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit"); 74998c2ecf20Sopenharmony_ci return -EINVAL; 75008c2ecf20Sopenharmony_ci } 75018c2ecf20Sopenharmony_ci 75028c2ecf20Sopenharmony_ci if (burst < policer_item->policer->min_burst) { 75038c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit"); 75048c2ecf20Sopenharmony_ci return -EINVAL; 75058c2ecf20Sopenharmony_ci } 75068c2ecf20Sopenharmony_ci 75078c2ecf20Sopenharmony_ci if (burst > policer_item->policer->max_burst) { 75088c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit"); 75098c2ecf20Sopenharmony_ci return -EINVAL; 75108c2ecf20Sopenharmony_ci } 75118c2ecf20Sopenharmony_ci 75128c2ecf20Sopenharmony_ci err = devlink->ops->trap_policer_set(devlink, policer_item->policer, 75138c2ecf20Sopenharmony_ci rate, burst, info->extack); 75148c2ecf20Sopenharmony_ci if (err) 75158c2ecf20Sopenharmony_ci return err; 75168c2ecf20Sopenharmony_ci 75178c2ecf20Sopenharmony_ci policer_item->rate = rate; 75188c2ecf20Sopenharmony_ci policer_item->burst = burst; 75198c2ecf20Sopenharmony_ci 75208c2ecf20Sopenharmony_ci return 0; 75218c2ecf20Sopenharmony_ci} 75228c2ecf20Sopenharmony_ci 75238c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb, 75248c2ecf20Sopenharmony_ci struct genl_info *info) 75258c2ecf20Sopenharmony_ci{ 75268c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 75278c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 75288c2ecf20Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 75298c2ecf20Sopenharmony_ci 75308c2ecf20Sopenharmony_ci if (list_empty(&devlink->trap_policer_list)) 75318c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 75328c2ecf20Sopenharmony_ci 75338c2ecf20Sopenharmony_ci if (!devlink->ops->trap_policer_set) 75348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 75358c2ecf20Sopenharmony_ci 75368c2ecf20Sopenharmony_ci policer_item = devlink_trap_policer_item_get_from_info(devlink, info); 75378c2ecf20Sopenharmony_ci if (!policer_item) { 75388c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer"); 75398c2ecf20Sopenharmony_ci return -ENOENT; 75408c2ecf20Sopenharmony_ci } 75418c2ecf20Sopenharmony_ci 75428c2ecf20Sopenharmony_ci return devlink_trap_policer_set(devlink, policer_item, info); 75438c2ecf20Sopenharmony_ci} 75448c2ecf20Sopenharmony_ci 75458c2ecf20Sopenharmony_cistatic const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 75468c2ecf20Sopenharmony_ci [DEVLINK_ATTR_UNSPEC] = { .strict_start_type = 75478c2ecf20Sopenharmony_ci DEVLINK_ATTR_TRAP_POLICER_ID }, 75488c2ecf20Sopenharmony_ci [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, 75498c2ecf20Sopenharmony_ci [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, 75508c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 }, 75518c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO, 75528c2ecf20Sopenharmony_ci DEVLINK_PORT_TYPE_IB), 75538c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 }, 75548c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 }, 75558c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 }, 75568c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 }, 75578c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 }, 75588c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 }, 75598c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 }, 75608c2ecf20Sopenharmony_ci [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 }, 75618c2ecf20Sopenharmony_ci [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY, 75628c2ecf20Sopenharmony_ci DEVLINK_ESWITCH_MODE_SWITCHDEV), 75638c2ecf20Sopenharmony_ci [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 }, 75648c2ecf20Sopenharmony_ci [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 }, 75658c2ecf20Sopenharmony_ci [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING }, 75668c2ecf20Sopenharmony_ci [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 }, 75678c2ecf20Sopenharmony_ci [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64}, 75688c2ecf20Sopenharmony_ci [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64}, 75698c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING }, 75708c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 }, 75718c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 }, 75728c2ecf20Sopenharmony_ci [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING }, 75738c2ecf20Sopenharmony_ci [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 }, 75748c2ecf20Sopenharmony_ci [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 }, 75758c2ecf20Sopenharmony_ci [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 }, 75768c2ecf20Sopenharmony_ci [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING }, 75778c2ecf20Sopenharmony_ci [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 }, 75788c2ecf20Sopenharmony_ci [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 }, 75798c2ecf20Sopenharmony_ci [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING }, 75808c2ecf20Sopenharmony_ci [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING }, 75818c2ecf20Sopenharmony_ci [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = 75828c2ecf20Sopenharmony_ci NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS), 75838c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING }, 75848c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 }, 75858c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING }, 75868c2ecf20Sopenharmony_ci [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 }, 75878c2ecf20Sopenharmony_ci [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 }, 75888c2ecf20Sopenharmony_ci [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 }, 75898c2ecf20Sopenharmony_ci [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 }, 75908c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 }, 75918c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 }, 75928c2ecf20Sopenharmony_ci [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 }, 75938c2ecf20Sopenharmony_ci [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED }, 75948c2ecf20Sopenharmony_ci [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 75958c2ecf20Sopenharmony_ci DEVLINK_RELOAD_ACTION_MAX), 75968c2ecf20Sopenharmony_ci [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), 75978c2ecf20Sopenharmony_ci}; 75988c2ecf20Sopenharmony_ci 75998c2ecf20Sopenharmony_cistatic const struct genl_small_ops devlink_nl_ops[] = { 76008c2ecf20Sopenharmony_ci { 76018c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_GET, 76028c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76038c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_get_doit, 76048c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_get_dumpit, 76058c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76068c2ecf20Sopenharmony_ci }, 76078c2ecf20Sopenharmony_ci { 76088c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_GET, 76098c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76108c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_get_doit, 76118c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_port_get_dumpit, 76128c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76138c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76148c2ecf20Sopenharmony_ci }, 76158c2ecf20Sopenharmony_ci { 76168c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_SET, 76178c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76188c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_set_doit, 76198c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76208c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76218c2ecf20Sopenharmony_ci }, 76228c2ecf20Sopenharmony_ci { 76238c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_SPLIT, 76248c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76258c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_split_doit, 76268c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76278c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 76288c2ecf20Sopenharmony_ci }, 76298c2ecf20Sopenharmony_ci { 76308c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_UNSPLIT, 76318c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76328c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_unsplit_doit, 76338c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76348c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 76358c2ecf20Sopenharmony_ci }, 76368c2ecf20Sopenharmony_ci { 76378c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_GET, 76388c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76398c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_get_doit, 76408c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_sb_get_dumpit, 76418c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76428c2ecf20Sopenharmony_ci }, 76438c2ecf20Sopenharmony_ci { 76448c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_POOL_GET, 76458c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76468c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_pool_get_doit, 76478c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_sb_pool_get_dumpit, 76488c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76498c2ecf20Sopenharmony_ci }, 76508c2ecf20Sopenharmony_ci { 76518c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_POOL_SET, 76528c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76538c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_pool_set_doit, 76548c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76558c2ecf20Sopenharmony_ci }, 76568c2ecf20Sopenharmony_ci { 76578c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_PORT_POOL_GET, 76588c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76598c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_port_pool_get_doit, 76608c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit, 76618c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76628c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76638c2ecf20Sopenharmony_ci }, 76648c2ecf20Sopenharmony_ci { 76658c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_PORT_POOL_SET, 76668c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76678c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_port_pool_set_doit, 76688c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76698c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76708c2ecf20Sopenharmony_ci }, 76718c2ecf20Sopenharmony_ci { 76728c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET, 76738c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76748c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit, 76758c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit, 76768c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76778c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 76788c2ecf20Sopenharmony_ci }, 76798c2ecf20Sopenharmony_ci { 76808c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET, 76818c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76828c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit, 76838c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76848c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 76858c2ecf20Sopenharmony_ci }, 76868c2ecf20Sopenharmony_ci { 76878c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT, 76888c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76898c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_occ_snapshot_doit, 76908c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76918c2ecf20Sopenharmony_ci }, 76928c2ecf20Sopenharmony_ci { 76938c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR, 76948c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 76958c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_sb_occ_max_clear_doit, 76968c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 76978c2ecf20Sopenharmony_ci }, 76988c2ecf20Sopenharmony_ci { 76998c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_ESWITCH_GET, 77008c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77018c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_eswitch_get_doit, 77028c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77038c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 77048c2ecf20Sopenharmony_ci }, 77058c2ecf20Sopenharmony_ci { 77068c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_ESWITCH_SET, 77078c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77088c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_eswitch_set_doit, 77098c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77108c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 77118c2ecf20Sopenharmony_ci }, 77128c2ecf20Sopenharmony_ci { 77138c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_DPIPE_TABLE_GET, 77148c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77158c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_dpipe_table_get, 77168c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77178c2ecf20Sopenharmony_ci }, 77188c2ecf20Sopenharmony_ci { 77198c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET, 77208c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77218c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_dpipe_entries_get, 77228c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77238c2ecf20Sopenharmony_ci }, 77248c2ecf20Sopenharmony_ci { 77258c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET, 77268c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77278c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_dpipe_headers_get, 77288c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77298c2ecf20Sopenharmony_ci }, 77308c2ecf20Sopenharmony_ci { 77318c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, 77328c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77338c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_dpipe_table_counters_set, 77348c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77358c2ecf20Sopenharmony_ci }, 77368c2ecf20Sopenharmony_ci { 77378c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_RESOURCE_SET, 77388c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77398c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_resource_set, 77408c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77418c2ecf20Sopenharmony_ci }, 77428c2ecf20Sopenharmony_ci { 77438c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_RESOURCE_DUMP, 77448c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77458c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_resource_dump, 77468c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77478c2ecf20Sopenharmony_ci }, 77488c2ecf20Sopenharmony_ci { 77498c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_RELOAD, 77508c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77518c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_reload, 77528c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77538c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, 77548c2ecf20Sopenharmony_ci }, 77558c2ecf20Sopenharmony_ci { 77568c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PARAM_GET, 77578c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77588c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_param_get_doit, 77598c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_param_get_dumpit, 77608c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77618c2ecf20Sopenharmony_ci }, 77628c2ecf20Sopenharmony_ci { 77638c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PARAM_SET, 77648c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77658c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_param_set_doit, 77668c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77678c2ecf20Sopenharmony_ci }, 77688c2ecf20Sopenharmony_ci { 77698c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_PARAM_GET, 77708c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77718c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_param_get_doit, 77728c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_port_param_get_dumpit, 77738c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 77748c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 77758c2ecf20Sopenharmony_ci }, 77768c2ecf20Sopenharmony_ci { 77778c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_PORT_PARAM_SET, 77788c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77798c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_port_param_set_doit, 77808c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77818c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, 77828c2ecf20Sopenharmony_ci }, 77838c2ecf20Sopenharmony_ci { 77848c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_REGION_GET, 77858c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77868c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_region_get_doit, 77878c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_region_get_dumpit, 77888c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77898c2ecf20Sopenharmony_ci }, 77908c2ecf20Sopenharmony_ci { 77918c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_REGION_NEW, 77928c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77938c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_region_new, 77948c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 77958c2ecf20Sopenharmony_ci }, 77968c2ecf20Sopenharmony_ci { 77978c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_REGION_DEL, 77988c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 77998c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_region_del, 78008c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78018c2ecf20Sopenharmony_ci }, 78028c2ecf20Sopenharmony_ci { 78038c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_REGION_READ, 78048c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | 78058c2ecf20Sopenharmony_ci GENL_DONT_VALIDATE_DUMP_STRICT, 78068c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_region_read_dumpit, 78078c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78088c2ecf20Sopenharmony_ci }, 78098c2ecf20Sopenharmony_ci { 78108c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_INFO_GET, 78118c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78128c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_info_get_doit, 78138c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_info_get_dumpit, 78148c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 78158c2ecf20Sopenharmony_ci }, 78168c2ecf20Sopenharmony_ci { 78178c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET, 78188c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78198c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_get_doit, 78208c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_health_reporter_get_dumpit, 78218c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78228c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78238c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 78248c2ecf20Sopenharmony_ci }, 78258c2ecf20Sopenharmony_ci { 78268c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET, 78278c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78288c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_set_doit, 78298c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78308c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78318c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78328c2ecf20Sopenharmony_ci }, 78338c2ecf20Sopenharmony_ci { 78348c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER, 78358c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78368c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_recover_doit, 78378c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78388c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78398c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78408c2ecf20Sopenharmony_ci }, 78418c2ecf20Sopenharmony_ci { 78428c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 78438c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78448c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_diagnose_doit, 78458c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78468c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78478c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78488c2ecf20Sopenharmony_ci }, 78498c2ecf20Sopenharmony_ci { 78508c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 78518c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | 78528c2ecf20Sopenharmony_ci GENL_DONT_VALIDATE_DUMP_STRICT, 78538c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit, 78548c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78558c2ecf20Sopenharmony_ci }, 78568c2ecf20Sopenharmony_ci { 78578c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, 78588c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78598c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_dump_clear_doit, 78608c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78618c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78628c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78638c2ecf20Sopenharmony_ci }, 78648c2ecf20Sopenharmony_ci { 78658c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST, 78668c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78678c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_health_reporter_test_doit, 78688c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78698c2ecf20Sopenharmony_ci .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT | 78708c2ecf20Sopenharmony_ci DEVLINK_NL_FLAG_NO_LOCK, 78718c2ecf20Sopenharmony_ci }, 78728c2ecf20Sopenharmony_ci { 78738c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_FLASH_UPDATE, 78748c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 78758c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_flash_update, 78768c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78778c2ecf20Sopenharmony_ci }, 78788c2ecf20Sopenharmony_ci { 78798c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_GET, 78808c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_get_doit, 78818c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_trap_get_dumpit, 78828c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 78838c2ecf20Sopenharmony_ci }, 78848c2ecf20Sopenharmony_ci { 78858c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_SET, 78868c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_set_doit, 78878c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78888c2ecf20Sopenharmony_ci }, 78898c2ecf20Sopenharmony_ci { 78908c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_GROUP_GET, 78918c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_group_get_doit, 78928c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_trap_group_get_dumpit, 78938c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 78948c2ecf20Sopenharmony_ci }, 78958c2ecf20Sopenharmony_ci { 78968c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_GROUP_SET, 78978c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_group_set_doit, 78988c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 78998c2ecf20Sopenharmony_ci }, 79008c2ecf20Sopenharmony_ci { 79018c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_POLICER_GET, 79028c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_policer_get_doit, 79038c2ecf20Sopenharmony_ci .dumpit = devlink_nl_cmd_trap_policer_get_dumpit, 79048c2ecf20Sopenharmony_ci /* can be retrieved by unprivileged users */ 79058c2ecf20Sopenharmony_ci }, 79068c2ecf20Sopenharmony_ci { 79078c2ecf20Sopenharmony_ci .cmd = DEVLINK_CMD_TRAP_POLICER_SET, 79088c2ecf20Sopenharmony_ci .doit = devlink_nl_cmd_trap_policer_set_doit, 79098c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 79108c2ecf20Sopenharmony_ci }, 79118c2ecf20Sopenharmony_ci}; 79128c2ecf20Sopenharmony_ci 79138c2ecf20Sopenharmony_cistatic struct genl_family devlink_nl_family __ro_after_init = { 79148c2ecf20Sopenharmony_ci .name = DEVLINK_GENL_NAME, 79158c2ecf20Sopenharmony_ci .version = DEVLINK_GENL_VERSION, 79168c2ecf20Sopenharmony_ci .maxattr = DEVLINK_ATTR_MAX, 79178c2ecf20Sopenharmony_ci .policy = devlink_nl_policy, 79188c2ecf20Sopenharmony_ci .netnsok = true, 79198c2ecf20Sopenharmony_ci .pre_doit = devlink_nl_pre_doit, 79208c2ecf20Sopenharmony_ci .post_doit = devlink_nl_post_doit, 79218c2ecf20Sopenharmony_ci .module = THIS_MODULE, 79228c2ecf20Sopenharmony_ci .small_ops = devlink_nl_ops, 79238c2ecf20Sopenharmony_ci .n_small_ops = ARRAY_SIZE(devlink_nl_ops), 79248c2ecf20Sopenharmony_ci .mcgrps = devlink_nl_mcgrps, 79258c2ecf20Sopenharmony_ci .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps), 79268c2ecf20Sopenharmony_ci}; 79278c2ecf20Sopenharmony_ci 79288c2ecf20Sopenharmony_cistatic bool devlink_reload_actions_valid(const struct devlink_ops *ops) 79298c2ecf20Sopenharmony_ci{ 79308c2ecf20Sopenharmony_ci const struct devlink_reload_combination *comb; 79318c2ecf20Sopenharmony_ci int i; 79328c2ecf20Sopenharmony_ci 79338c2ecf20Sopenharmony_ci if (!devlink_reload_supported(ops)) { 79348c2ecf20Sopenharmony_ci if (WARN_ON(ops->reload_actions)) 79358c2ecf20Sopenharmony_ci return false; 79368c2ecf20Sopenharmony_ci return true; 79378c2ecf20Sopenharmony_ci } 79388c2ecf20Sopenharmony_ci 79398c2ecf20Sopenharmony_ci if (WARN_ON(!ops->reload_actions || 79408c2ecf20Sopenharmony_ci ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || 79418c2ecf20Sopenharmony_ci ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX))) 79428c2ecf20Sopenharmony_ci return false; 79438c2ecf20Sopenharmony_ci 79448c2ecf20Sopenharmony_ci if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) || 79458c2ecf20Sopenharmony_ci ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX))) 79468c2ecf20Sopenharmony_ci return false; 79478c2ecf20Sopenharmony_ci 79488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) { 79498c2ecf20Sopenharmony_ci comb = &devlink_reload_invalid_combinations[i]; 79508c2ecf20Sopenharmony_ci if (ops->reload_actions == BIT(comb->action) && 79518c2ecf20Sopenharmony_ci ops->reload_limits == BIT(comb->limit)) 79528c2ecf20Sopenharmony_ci return false; 79538c2ecf20Sopenharmony_ci } 79548c2ecf20Sopenharmony_ci return true; 79558c2ecf20Sopenharmony_ci} 79568c2ecf20Sopenharmony_ci 79578c2ecf20Sopenharmony_ci/** 79588c2ecf20Sopenharmony_ci * devlink_alloc - Allocate new devlink instance resources 79598c2ecf20Sopenharmony_ci * 79608c2ecf20Sopenharmony_ci * @ops: ops 79618c2ecf20Sopenharmony_ci * @priv_size: size of user private data 79628c2ecf20Sopenharmony_ci * 79638c2ecf20Sopenharmony_ci * Allocate new devlink instance resources, including devlink index 79648c2ecf20Sopenharmony_ci * and name. 79658c2ecf20Sopenharmony_ci */ 79668c2ecf20Sopenharmony_cistruct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) 79678c2ecf20Sopenharmony_ci{ 79688c2ecf20Sopenharmony_ci struct devlink *devlink; 79698c2ecf20Sopenharmony_ci 79708c2ecf20Sopenharmony_ci if (WARN_ON(!ops)) 79718c2ecf20Sopenharmony_ci return NULL; 79728c2ecf20Sopenharmony_ci 79738c2ecf20Sopenharmony_ci if (!devlink_reload_actions_valid(ops)) 79748c2ecf20Sopenharmony_ci return NULL; 79758c2ecf20Sopenharmony_ci 79768c2ecf20Sopenharmony_ci devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL); 79778c2ecf20Sopenharmony_ci if (!devlink) 79788c2ecf20Sopenharmony_ci return NULL; 79798c2ecf20Sopenharmony_ci devlink->ops = ops; 79808c2ecf20Sopenharmony_ci xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); 79818c2ecf20Sopenharmony_ci __devlink_net_set(devlink, &init_net); 79828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->port_list); 79838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->sb_list); 79848c2ecf20Sopenharmony_ci INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list); 79858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->resource_list); 79868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->param_list); 79878c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->region_list); 79888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->reporter_list); 79898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->trap_list); 79908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->trap_group_list); 79918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink->trap_policer_list); 79928c2ecf20Sopenharmony_ci mutex_init(&devlink->lock); 79938c2ecf20Sopenharmony_ci mutex_init(&devlink->reporters_lock); 79948c2ecf20Sopenharmony_ci return devlink; 79958c2ecf20Sopenharmony_ci} 79968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_alloc); 79978c2ecf20Sopenharmony_ci 79988c2ecf20Sopenharmony_ci/** 79998c2ecf20Sopenharmony_ci * devlink_register - Register devlink instance 80008c2ecf20Sopenharmony_ci * 80018c2ecf20Sopenharmony_ci * @devlink: devlink 80028c2ecf20Sopenharmony_ci * @dev: parent device 80038c2ecf20Sopenharmony_ci */ 80048c2ecf20Sopenharmony_ciint devlink_register(struct devlink *devlink, struct device *dev) 80058c2ecf20Sopenharmony_ci{ 80068c2ecf20Sopenharmony_ci devlink->dev = dev; 80078c2ecf20Sopenharmony_ci devlink->registered = true; 80088c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 80098c2ecf20Sopenharmony_ci list_add_tail(&devlink->list, &devlink_list); 80108c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_NEW); 80118c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 80128c2ecf20Sopenharmony_ci return 0; 80138c2ecf20Sopenharmony_ci} 80148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_register); 80158c2ecf20Sopenharmony_ci 80168c2ecf20Sopenharmony_ci/** 80178c2ecf20Sopenharmony_ci * devlink_unregister - Unregister devlink instance 80188c2ecf20Sopenharmony_ci * 80198c2ecf20Sopenharmony_ci * @devlink: devlink 80208c2ecf20Sopenharmony_ci */ 80218c2ecf20Sopenharmony_civoid devlink_unregister(struct devlink *devlink) 80228c2ecf20Sopenharmony_ci{ 80238c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 80248c2ecf20Sopenharmony_ci WARN_ON(devlink_reload_supported(devlink->ops) && 80258c2ecf20Sopenharmony_ci devlink->reload_enabled); 80268c2ecf20Sopenharmony_ci devlink_notify(devlink, DEVLINK_CMD_DEL); 80278c2ecf20Sopenharmony_ci list_del(&devlink->list); 80288c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 80298c2ecf20Sopenharmony_ci} 80308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_unregister); 80318c2ecf20Sopenharmony_ci 80328c2ecf20Sopenharmony_ci/** 80338c2ecf20Sopenharmony_ci * devlink_reload_enable - Enable reload of devlink instance 80348c2ecf20Sopenharmony_ci * 80358c2ecf20Sopenharmony_ci * @devlink: devlink 80368c2ecf20Sopenharmony_ci * 80378c2ecf20Sopenharmony_ci * Should be called at end of device initialization 80388c2ecf20Sopenharmony_ci * process when reload operation is supported. 80398c2ecf20Sopenharmony_ci */ 80408c2ecf20Sopenharmony_civoid devlink_reload_enable(struct devlink *devlink) 80418c2ecf20Sopenharmony_ci{ 80428c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 80438c2ecf20Sopenharmony_ci devlink->reload_enabled = true; 80448c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 80458c2ecf20Sopenharmony_ci} 80468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_reload_enable); 80478c2ecf20Sopenharmony_ci 80488c2ecf20Sopenharmony_ci/** 80498c2ecf20Sopenharmony_ci * devlink_reload_disable - Disable reload of devlink instance 80508c2ecf20Sopenharmony_ci * 80518c2ecf20Sopenharmony_ci * @devlink: devlink 80528c2ecf20Sopenharmony_ci * 80538c2ecf20Sopenharmony_ci * Should be called at the beginning of device cleanup 80548c2ecf20Sopenharmony_ci * process when reload operation is supported. 80558c2ecf20Sopenharmony_ci */ 80568c2ecf20Sopenharmony_civoid devlink_reload_disable(struct devlink *devlink) 80578c2ecf20Sopenharmony_ci{ 80588c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 80598c2ecf20Sopenharmony_ci /* Mutex is taken which ensures that no reload operation is in 80608c2ecf20Sopenharmony_ci * progress while setting up forbidded flag. 80618c2ecf20Sopenharmony_ci */ 80628c2ecf20Sopenharmony_ci devlink->reload_enabled = false; 80638c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 80648c2ecf20Sopenharmony_ci} 80658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_reload_disable); 80668c2ecf20Sopenharmony_ci 80678c2ecf20Sopenharmony_ci/** 80688c2ecf20Sopenharmony_ci * devlink_free - Free devlink instance resources 80698c2ecf20Sopenharmony_ci * 80708c2ecf20Sopenharmony_ci * @devlink: devlink 80718c2ecf20Sopenharmony_ci */ 80728c2ecf20Sopenharmony_civoid devlink_free(struct devlink *devlink) 80738c2ecf20Sopenharmony_ci{ 80748c2ecf20Sopenharmony_ci mutex_destroy(&devlink->reporters_lock); 80758c2ecf20Sopenharmony_ci mutex_destroy(&devlink->lock); 80768c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->trap_policer_list)); 80778c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->trap_group_list)); 80788c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->trap_list)); 80798c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->reporter_list)); 80808c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->region_list)); 80818c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->param_list)); 80828c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->resource_list)); 80838c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->dpipe_table_list)); 80848c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->sb_list)); 80858c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink->port_list)); 80868c2ecf20Sopenharmony_ci 80878c2ecf20Sopenharmony_ci xa_destroy(&devlink->snapshot_ids); 80888c2ecf20Sopenharmony_ci 80898c2ecf20Sopenharmony_ci kfree(devlink); 80908c2ecf20Sopenharmony_ci} 80918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_free); 80928c2ecf20Sopenharmony_ci 80938c2ecf20Sopenharmony_cistatic void devlink_port_type_warn(struct work_struct *work) 80948c2ecf20Sopenharmony_ci{ 80958c2ecf20Sopenharmony_ci struct devlink_port *port = container_of(to_delayed_work(work), 80968c2ecf20Sopenharmony_ci struct devlink_port, 80978c2ecf20Sopenharmony_ci type_warn_dw); 80988c2ecf20Sopenharmony_ci dev_warn(port->devlink->dev, "Type was not set for devlink port."); 80998c2ecf20Sopenharmony_ci} 81008c2ecf20Sopenharmony_ci 81018c2ecf20Sopenharmony_cistatic bool devlink_port_type_should_warn(struct devlink_port *devlink_port) 81028c2ecf20Sopenharmony_ci{ 81038c2ecf20Sopenharmony_ci /* Ignore CPU and DSA flavours. */ 81048c2ecf20Sopenharmony_ci return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU && 81058c2ecf20Sopenharmony_ci devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA && 81068c2ecf20Sopenharmony_ci devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED; 81078c2ecf20Sopenharmony_ci} 81088c2ecf20Sopenharmony_ci 81098c2ecf20Sopenharmony_ci#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600) 81108c2ecf20Sopenharmony_ci 81118c2ecf20Sopenharmony_cistatic void devlink_port_type_warn_schedule(struct devlink_port *devlink_port) 81128c2ecf20Sopenharmony_ci{ 81138c2ecf20Sopenharmony_ci if (!devlink_port_type_should_warn(devlink_port)) 81148c2ecf20Sopenharmony_ci return; 81158c2ecf20Sopenharmony_ci /* Schedule a work to WARN in case driver does not set port 81168c2ecf20Sopenharmony_ci * type within timeout. 81178c2ecf20Sopenharmony_ci */ 81188c2ecf20Sopenharmony_ci schedule_delayed_work(&devlink_port->type_warn_dw, 81198c2ecf20Sopenharmony_ci DEVLINK_PORT_TYPE_WARN_TIMEOUT); 81208c2ecf20Sopenharmony_ci} 81218c2ecf20Sopenharmony_ci 81228c2ecf20Sopenharmony_cistatic void devlink_port_type_warn_cancel(struct devlink_port *devlink_port) 81238c2ecf20Sopenharmony_ci{ 81248c2ecf20Sopenharmony_ci if (!devlink_port_type_should_warn(devlink_port)) 81258c2ecf20Sopenharmony_ci return; 81268c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&devlink_port->type_warn_dw); 81278c2ecf20Sopenharmony_ci} 81288c2ecf20Sopenharmony_ci 81298c2ecf20Sopenharmony_ci/** 81308c2ecf20Sopenharmony_ci * devlink_port_register - Register devlink port 81318c2ecf20Sopenharmony_ci * 81328c2ecf20Sopenharmony_ci * @devlink: devlink 81338c2ecf20Sopenharmony_ci * @devlink_port: devlink port 81348c2ecf20Sopenharmony_ci * @port_index: driver-specific numerical identifier of the port 81358c2ecf20Sopenharmony_ci * 81368c2ecf20Sopenharmony_ci * Register devlink port with provided port index. User can use 81378c2ecf20Sopenharmony_ci * any indexing, even hw-related one. devlink_port structure 81388c2ecf20Sopenharmony_ci * is convenient to be embedded inside user driver private structure. 81398c2ecf20Sopenharmony_ci * Note that the caller should take care of zeroing the devlink_port 81408c2ecf20Sopenharmony_ci * structure. 81418c2ecf20Sopenharmony_ci */ 81428c2ecf20Sopenharmony_ciint devlink_port_register(struct devlink *devlink, 81438c2ecf20Sopenharmony_ci struct devlink_port *devlink_port, 81448c2ecf20Sopenharmony_ci unsigned int port_index) 81458c2ecf20Sopenharmony_ci{ 81468c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 81478c2ecf20Sopenharmony_ci if (devlink_port_index_exists(devlink, port_index)) { 81488c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 81498c2ecf20Sopenharmony_ci return -EEXIST; 81508c2ecf20Sopenharmony_ci } 81518c2ecf20Sopenharmony_ci devlink_port->devlink = devlink; 81528c2ecf20Sopenharmony_ci devlink_port->index = port_index; 81538c2ecf20Sopenharmony_ci devlink_port->registered = true; 81548c2ecf20Sopenharmony_ci spin_lock_init(&devlink_port->type_lock); 81558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink_port->reporter_list); 81568c2ecf20Sopenharmony_ci mutex_init(&devlink_port->reporters_lock); 81578c2ecf20Sopenharmony_ci list_add_tail(&devlink_port->list, &devlink->port_list); 81588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink_port->param_list); 81598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&devlink_port->region_list); 81608c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 81618c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn); 81628c2ecf20Sopenharmony_ci devlink_port_type_warn_schedule(devlink_port); 81638c2ecf20Sopenharmony_ci devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 81648c2ecf20Sopenharmony_ci return 0; 81658c2ecf20Sopenharmony_ci} 81668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_register); 81678c2ecf20Sopenharmony_ci 81688c2ecf20Sopenharmony_ci/** 81698c2ecf20Sopenharmony_ci * devlink_port_unregister - Unregister devlink port 81708c2ecf20Sopenharmony_ci * 81718c2ecf20Sopenharmony_ci * @devlink_port: devlink port 81728c2ecf20Sopenharmony_ci */ 81738c2ecf20Sopenharmony_civoid devlink_port_unregister(struct devlink_port *devlink_port) 81748c2ecf20Sopenharmony_ci{ 81758c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 81768c2ecf20Sopenharmony_ci 81778c2ecf20Sopenharmony_ci devlink_port_type_warn_cancel(devlink_port); 81788c2ecf20Sopenharmony_ci devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL); 81798c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 81808c2ecf20Sopenharmony_ci list_del(&devlink_port->list); 81818c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 81828c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink_port->reporter_list)); 81838c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&devlink_port->region_list)); 81848c2ecf20Sopenharmony_ci mutex_destroy(&devlink_port->reporters_lock); 81858c2ecf20Sopenharmony_ci} 81868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_unregister); 81878c2ecf20Sopenharmony_ci 81888c2ecf20Sopenharmony_cistatic void __devlink_port_type_set(struct devlink_port *devlink_port, 81898c2ecf20Sopenharmony_ci enum devlink_port_type type, 81908c2ecf20Sopenharmony_ci void *type_dev) 81918c2ecf20Sopenharmony_ci{ 81928c2ecf20Sopenharmony_ci if (WARN_ON(!devlink_port->registered)) 81938c2ecf20Sopenharmony_ci return; 81948c2ecf20Sopenharmony_ci devlink_port_type_warn_cancel(devlink_port); 81958c2ecf20Sopenharmony_ci spin_lock_bh(&devlink_port->type_lock); 81968c2ecf20Sopenharmony_ci devlink_port->type = type; 81978c2ecf20Sopenharmony_ci devlink_port->type_dev = type_dev; 81988c2ecf20Sopenharmony_ci spin_unlock_bh(&devlink_port->type_lock); 81998c2ecf20Sopenharmony_ci devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 82008c2ecf20Sopenharmony_ci} 82018c2ecf20Sopenharmony_ci 82028c2ecf20Sopenharmony_cistatic void devlink_port_type_netdev_checks(struct devlink_port *devlink_port, 82038c2ecf20Sopenharmony_ci struct net_device *netdev) 82048c2ecf20Sopenharmony_ci{ 82058c2ecf20Sopenharmony_ci const struct net_device_ops *ops = netdev->netdev_ops; 82068c2ecf20Sopenharmony_ci 82078c2ecf20Sopenharmony_ci /* If driver registers devlink port, it should set devlink port 82088c2ecf20Sopenharmony_ci * attributes accordingly so the compat functions are called 82098c2ecf20Sopenharmony_ci * and the original ops are not used. 82108c2ecf20Sopenharmony_ci */ 82118c2ecf20Sopenharmony_ci if (ops->ndo_get_phys_port_name) { 82128c2ecf20Sopenharmony_ci /* Some drivers use the same set of ndos for netdevs 82138c2ecf20Sopenharmony_ci * that have devlink_port registered and also for 82148c2ecf20Sopenharmony_ci * those who don't. Make sure that ndo_get_phys_port_name 82158c2ecf20Sopenharmony_ci * returns -EOPNOTSUPP here in case it is defined. 82168c2ecf20Sopenharmony_ci * Warn if not. 82178c2ecf20Sopenharmony_ci */ 82188c2ecf20Sopenharmony_ci char name[IFNAMSIZ]; 82198c2ecf20Sopenharmony_ci int err; 82208c2ecf20Sopenharmony_ci 82218c2ecf20Sopenharmony_ci err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name)); 82228c2ecf20Sopenharmony_ci WARN_ON(err != -EOPNOTSUPP); 82238c2ecf20Sopenharmony_ci } 82248c2ecf20Sopenharmony_ci if (ops->ndo_get_port_parent_id) { 82258c2ecf20Sopenharmony_ci /* Some drivers use the same set of ndos for netdevs 82268c2ecf20Sopenharmony_ci * that have devlink_port registered and also for 82278c2ecf20Sopenharmony_ci * those who don't. Make sure that ndo_get_port_parent_id 82288c2ecf20Sopenharmony_ci * returns -EOPNOTSUPP here in case it is defined. 82298c2ecf20Sopenharmony_ci * Warn if not. 82308c2ecf20Sopenharmony_ci */ 82318c2ecf20Sopenharmony_ci struct netdev_phys_item_id ppid; 82328c2ecf20Sopenharmony_ci int err; 82338c2ecf20Sopenharmony_ci 82348c2ecf20Sopenharmony_ci err = ops->ndo_get_port_parent_id(netdev, &ppid); 82358c2ecf20Sopenharmony_ci WARN_ON(err != -EOPNOTSUPP); 82368c2ecf20Sopenharmony_ci } 82378c2ecf20Sopenharmony_ci} 82388c2ecf20Sopenharmony_ci 82398c2ecf20Sopenharmony_ci/** 82408c2ecf20Sopenharmony_ci * devlink_port_type_eth_set - Set port type to Ethernet 82418c2ecf20Sopenharmony_ci * 82428c2ecf20Sopenharmony_ci * @devlink_port: devlink port 82438c2ecf20Sopenharmony_ci * @netdev: related netdevice 82448c2ecf20Sopenharmony_ci */ 82458c2ecf20Sopenharmony_civoid devlink_port_type_eth_set(struct devlink_port *devlink_port, 82468c2ecf20Sopenharmony_ci struct net_device *netdev) 82478c2ecf20Sopenharmony_ci{ 82488c2ecf20Sopenharmony_ci if (netdev) 82498c2ecf20Sopenharmony_ci devlink_port_type_netdev_checks(devlink_port, netdev); 82508c2ecf20Sopenharmony_ci else 82518c2ecf20Sopenharmony_ci dev_warn(devlink_port->devlink->dev, 82528c2ecf20Sopenharmony_ci "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n", 82538c2ecf20Sopenharmony_ci devlink_port->index); 82548c2ecf20Sopenharmony_ci 82558c2ecf20Sopenharmony_ci __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev); 82568c2ecf20Sopenharmony_ci} 82578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_eth_set); 82588c2ecf20Sopenharmony_ci 82598c2ecf20Sopenharmony_ci/** 82608c2ecf20Sopenharmony_ci * devlink_port_type_ib_set - Set port type to InfiniBand 82618c2ecf20Sopenharmony_ci * 82628c2ecf20Sopenharmony_ci * @devlink_port: devlink port 82638c2ecf20Sopenharmony_ci * @ibdev: related IB device 82648c2ecf20Sopenharmony_ci */ 82658c2ecf20Sopenharmony_civoid devlink_port_type_ib_set(struct devlink_port *devlink_port, 82668c2ecf20Sopenharmony_ci struct ib_device *ibdev) 82678c2ecf20Sopenharmony_ci{ 82688c2ecf20Sopenharmony_ci __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev); 82698c2ecf20Sopenharmony_ci} 82708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_ib_set); 82718c2ecf20Sopenharmony_ci 82728c2ecf20Sopenharmony_ci/** 82738c2ecf20Sopenharmony_ci * devlink_port_type_clear - Clear port type 82748c2ecf20Sopenharmony_ci * 82758c2ecf20Sopenharmony_ci * @devlink_port: devlink port 82768c2ecf20Sopenharmony_ci */ 82778c2ecf20Sopenharmony_civoid devlink_port_type_clear(struct devlink_port *devlink_port) 82788c2ecf20Sopenharmony_ci{ 82798c2ecf20Sopenharmony_ci __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL); 82808c2ecf20Sopenharmony_ci devlink_port_type_warn_schedule(devlink_port); 82818c2ecf20Sopenharmony_ci} 82828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_clear); 82838c2ecf20Sopenharmony_ci 82848c2ecf20Sopenharmony_cistatic int __devlink_port_attrs_set(struct devlink_port *devlink_port, 82858c2ecf20Sopenharmony_ci enum devlink_port_flavour flavour) 82868c2ecf20Sopenharmony_ci{ 82878c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs = &devlink_port->attrs; 82888c2ecf20Sopenharmony_ci 82898c2ecf20Sopenharmony_ci devlink_port->attrs_set = true; 82908c2ecf20Sopenharmony_ci attrs->flavour = flavour; 82918c2ecf20Sopenharmony_ci if (attrs->switch_id.id_len) { 82928c2ecf20Sopenharmony_ci devlink_port->switch_port = true; 82938c2ecf20Sopenharmony_ci if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN)) 82948c2ecf20Sopenharmony_ci attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN; 82958c2ecf20Sopenharmony_ci } else { 82968c2ecf20Sopenharmony_ci devlink_port->switch_port = false; 82978c2ecf20Sopenharmony_ci } 82988c2ecf20Sopenharmony_ci return 0; 82998c2ecf20Sopenharmony_ci} 83008c2ecf20Sopenharmony_ci 83018c2ecf20Sopenharmony_ci/** 83028c2ecf20Sopenharmony_ci * devlink_port_attrs_set - Set port attributes 83038c2ecf20Sopenharmony_ci * 83048c2ecf20Sopenharmony_ci * @devlink_port: devlink port 83058c2ecf20Sopenharmony_ci * @attrs: devlink port attrs 83068c2ecf20Sopenharmony_ci */ 83078c2ecf20Sopenharmony_civoid devlink_port_attrs_set(struct devlink_port *devlink_port, 83088c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs) 83098c2ecf20Sopenharmony_ci{ 83108c2ecf20Sopenharmony_ci int ret; 83118c2ecf20Sopenharmony_ci 83128c2ecf20Sopenharmony_ci if (WARN_ON(devlink_port->registered)) 83138c2ecf20Sopenharmony_ci return; 83148c2ecf20Sopenharmony_ci devlink_port->attrs = *attrs; 83158c2ecf20Sopenharmony_ci ret = __devlink_port_attrs_set(devlink_port, attrs->flavour); 83168c2ecf20Sopenharmony_ci if (ret) 83178c2ecf20Sopenharmony_ci return; 83188c2ecf20Sopenharmony_ci WARN_ON(attrs->splittable && attrs->split); 83198c2ecf20Sopenharmony_ci} 83208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_set); 83218c2ecf20Sopenharmony_ci 83228c2ecf20Sopenharmony_ci/** 83238c2ecf20Sopenharmony_ci * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes 83248c2ecf20Sopenharmony_ci * 83258c2ecf20Sopenharmony_ci * @devlink_port: devlink port 83268c2ecf20Sopenharmony_ci * @controller: associated controller number for the devlink port instance 83278c2ecf20Sopenharmony_ci * @pf: associated PF for the devlink port instance 83288c2ecf20Sopenharmony_ci * @external: indicates if the port is for an external controller 83298c2ecf20Sopenharmony_ci */ 83308c2ecf20Sopenharmony_civoid devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller, 83318c2ecf20Sopenharmony_ci u16 pf, bool external) 83328c2ecf20Sopenharmony_ci{ 83338c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs = &devlink_port->attrs; 83348c2ecf20Sopenharmony_ci int ret; 83358c2ecf20Sopenharmony_ci 83368c2ecf20Sopenharmony_ci if (WARN_ON(devlink_port->registered)) 83378c2ecf20Sopenharmony_ci return; 83388c2ecf20Sopenharmony_ci ret = __devlink_port_attrs_set(devlink_port, 83398c2ecf20Sopenharmony_ci DEVLINK_PORT_FLAVOUR_PCI_PF); 83408c2ecf20Sopenharmony_ci if (ret) 83418c2ecf20Sopenharmony_ci return; 83428c2ecf20Sopenharmony_ci attrs->pci_pf.controller = controller; 83438c2ecf20Sopenharmony_ci attrs->pci_pf.pf = pf; 83448c2ecf20Sopenharmony_ci attrs->pci_pf.external = external; 83458c2ecf20Sopenharmony_ci} 83468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set); 83478c2ecf20Sopenharmony_ci 83488c2ecf20Sopenharmony_ci/** 83498c2ecf20Sopenharmony_ci * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes 83508c2ecf20Sopenharmony_ci * 83518c2ecf20Sopenharmony_ci * @devlink_port: devlink port 83528c2ecf20Sopenharmony_ci * @controller: associated controller number for the devlink port instance 83538c2ecf20Sopenharmony_ci * @pf: associated PF for the devlink port instance 83548c2ecf20Sopenharmony_ci * @vf: associated VF of a PF for the devlink port instance 83558c2ecf20Sopenharmony_ci * @external: indicates if the port is for an external controller 83568c2ecf20Sopenharmony_ci */ 83578c2ecf20Sopenharmony_civoid devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, 83588c2ecf20Sopenharmony_ci u16 pf, u16 vf, bool external) 83598c2ecf20Sopenharmony_ci{ 83608c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs = &devlink_port->attrs; 83618c2ecf20Sopenharmony_ci int ret; 83628c2ecf20Sopenharmony_ci 83638c2ecf20Sopenharmony_ci if (WARN_ON(devlink_port->registered)) 83648c2ecf20Sopenharmony_ci return; 83658c2ecf20Sopenharmony_ci ret = __devlink_port_attrs_set(devlink_port, 83668c2ecf20Sopenharmony_ci DEVLINK_PORT_FLAVOUR_PCI_VF); 83678c2ecf20Sopenharmony_ci if (ret) 83688c2ecf20Sopenharmony_ci return; 83698c2ecf20Sopenharmony_ci attrs->pci_vf.controller = controller; 83708c2ecf20Sopenharmony_ci attrs->pci_vf.pf = pf; 83718c2ecf20Sopenharmony_ci attrs->pci_vf.vf = vf; 83728c2ecf20Sopenharmony_ci attrs->pci_vf.external = external; 83738c2ecf20Sopenharmony_ci} 83748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set); 83758c2ecf20Sopenharmony_ci 83768c2ecf20Sopenharmony_cistatic int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, 83778c2ecf20Sopenharmony_ci char *name, size_t len) 83788c2ecf20Sopenharmony_ci{ 83798c2ecf20Sopenharmony_ci struct devlink_port_attrs *attrs = &devlink_port->attrs; 83808c2ecf20Sopenharmony_ci int n = 0; 83818c2ecf20Sopenharmony_ci 83828c2ecf20Sopenharmony_ci if (!devlink_port->attrs_set) 83838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 83848c2ecf20Sopenharmony_ci 83858c2ecf20Sopenharmony_ci switch (attrs->flavour) { 83868c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PHYSICAL: 83878c2ecf20Sopenharmony_ci if (!attrs->split) 83888c2ecf20Sopenharmony_ci n = snprintf(name, len, "p%u", attrs->phys.port_number); 83898c2ecf20Sopenharmony_ci else 83908c2ecf20Sopenharmony_ci n = snprintf(name, len, "p%us%u", 83918c2ecf20Sopenharmony_ci attrs->phys.port_number, 83928c2ecf20Sopenharmony_ci attrs->phys.split_subport_number); 83938c2ecf20Sopenharmony_ci break; 83948c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_CPU: 83958c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_DSA: 83968c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_UNUSED: 83978c2ecf20Sopenharmony_ci /* As CPU and DSA ports do not have a netdevice associated 83988c2ecf20Sopenharmony_ci * case should not ever happen. 83998c2ecf20Sopenharmony_ci */ 84008c2ecf20Sopenharmony_ci WARN_ON(1); 84018c2ecf20Sopenharmony_ci return -EINVAL; 84028c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PCI_PF: 84038c2ecf20Sopenharmony_ci if (attrs->pci_pf.external) { 84048c2ecf20Sopenharmony_ci n = snprintf(name, len, "c%u", attrs->pci_pf.controller); 84058c2ecf20Sopenharmony_ci if (n >= len) 84068c2ecf20Sopenharmony_ci return -EINVAL; 84078c2ecf20Sopenharmony_ci len -= n; 84088c2ecf20Sopenharmony_ci name += n; 84098c2ecf20Sopenharmony_ci } 84108c2ecf20Sopenharmony_ci n = snprintf(name, len, "pf%u", attrs->pci_pf.pf); 84118c2ecf20Sopenharmony_ci break; 84128c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_PCI_VF: 84138c2ecf20Sopenharmony_ci if (attrs->pci_vf.external) { 84148c2ecf20Sopenharmony_ci n = snprintf(name, len, "c%u", attrs->pci_vf.controller); 84158c2ecf20Sopenharmony_ci if (n >= len) 84168c2ecf20Sopenharmony_ci return -EINVAL; 84178c2ecf20Sopenharmony_ci len -= n; 84188c2ecf20Sopenharmony_ci name += n; 84198c2ecf20Sopenharmony_ci } 84208c2ecf20Sopenharmony_ci n = snprintf(name, len, "pf%uvf%u", 84218c2ecf20Sopenharmony_ci attrs->pci_vf.pf, attrs->pci_vf.vf); 84228c2ecf20Sopenharmony_ci break; 84238c2ecf20Sopenharmony_ci case DEVLINK_PORT_FLAVOUR_VIRTUAL: 84248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 84258c2ecf20Sopenharmony_ci } 84268c2ecf20Sopenharmony_ci 84278c2ecf20Sopenharmony_ci if (n >= len) 84288c2ecf20Sopenharmony_ci return -EINVAL; 84298c2ecf20Sopenharmony_ci 84308c2ecf20Sopenharmony_ci return 0; 84318c2ecf20Sopenharmony_ci} 84328c2ecf20Sopenharmony_ci 84338c2ecf20Sopenharmony_ciint devlink_sb_register(struct devlink *devlink, unsigned int sb_index, 84348c2ecf20Sopenharmony_ci u32 size, u16 ingress_pools_count, 84358c2ecf20Sopenharmony_ci u16 egress_pools_count, u16 ingress_tc_count, 84368c2ecf20Sopenharmony_ci u16 egress_tc_count) 84378c2ecf20Sopenharmony_ci{ 84388c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 84398c2ecf20Sopenharmony_ci int err = 0; 84408c2ecf20Sopenharmony_ci 84418c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 84428c2ecf20Sopenharmony_ci if (devlink_sb_index_exists(devlink, sb_index)) { 84438c2ecf20Sopenharmony_ci err = -EEXIST; 84448c2ecf20Sopenharmony_ci goto unlock; 84458c2ecf20Sopenharmony_ci } 84468c2ecf20Sopenharmony_ci 84478c2ecf20Sopenharmony_ci devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL); 84488c2ecf20Sopenharmony_ci if (!devlink_sb) { 84498c2ecf20Sopenharmony_ci err = -ENOMEM; 84508c2ecf20Sopenharmony_ci goto unlock; 84518c2ecf20Sopenharmony_ci } 84528c2ecf20Sopenharmony_ci devlink_sb->index = sb_index; 84538c2ecf20Sopenharmony_ci devlink_sb->size = size; 84548c2ecf20Sopenharmony_ci devlink_sb->ingress_pools_count = ingress_pools_count; 84558c2ecf20Sopenharmony_ci devlink_sb->egress_pools_count = egress_pools_count; 84568c2ecf20Sopenharmony_ci devlink_sb->ingress_tc_count = ingress_tc_count; 84578c2ecf20Sopenharmony_ci devlink_sb->egress_tc_count = egress_tc_count; 84588c2ecf20Sopenharmony_ci list_add_tail(&devlink_sb->list, &devlink->sb_list); 84598c2ecf20Sopenharmony_ciunlock: 84608c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 84618c2ecf20Sopenharmony_ci return err; 84628c2ecf20Sopenharmony_ci} 84638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_sb_register); 84648c2ecf20Sopenharmony_ci 84658c2ecf20Sopenharmony_civoid devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index) 84668c2ecf20Sopenharmony_ci{ 84678c2ecf20Sopenharmony_ci struct devlink_sb *devlink_sb; 84688c2ecf20Sopenharmony_ci 84698c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 84708c2ecf20Sopenharmony_ci devlink_sb = devlink_sb_get_by_index(devlink, sb_index); 84718c2ecf20Sopenharmony_ci WARN_ON(!devlink_sb); 84728c2ecf20Sopenharmony_ci list_del(&devlink_sb->list); 84738c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 84748c2ecf20Sopenharmony_ci kfree(devlink_sb); 84758c2ecf20Sopenharmony_ci} 84768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_sb_unregister); 84778c2ecf20Sopenharmony_ci 84788c2ecf20Sopenharmony_ci/** 84798c2ecf20Sopenharmony_ci * devlink_dpipe_headers_register - register dpipe headers 84808c2ecf20Sopenharmony_ci * 84818c2ecf20Sopenharmony_ci * @devlink: devlink 84828c2ecf20Sopenharmony_ci * @dpipe_headers: dpipe header array 84838c2ecf20Sopenharmony_ci * 84848c2ecf20Sopenharmony_ci * Register the headers supported by hardware. 84858c2ecf20Sopenharmony_ci */ 84868c2ecf20Sopenharmony_ciint devlink_dpipe_headers_register(struct devlink *devlink, 84878c2ecf20Sopenharmony_ci struct devlink_dpipe_headers *dpipe_headers) 84888c2ecf20Sopenharmony_ci{ 84898c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 84908c2ecf20Sopenharmony_ci devlink->dpipe_headers = dpipe_headers; 84918c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 84928c2ecf20Sopenharmony_ci return 0; 84938c2ecf20Sopenharmony_ci} 84948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_headers_register); 84958c2ecf20Sopenharmony_ci 84968c2ecf20Sopenharmony_ci/** 84978c2ecf20Sopenharmony_ci * devlink_dpipe_headers_unregister - unregister dpipe headers 84988c2ecf20Sopenharmony_ci * 84998c2ecf20Sopenharmony_ci * @devlink: devlink 85008c2ecf20Sopenharmony_ci * 85018c2ecf20Sopenharmony_ci * Unregister the headers supported by hardware. 85028c2ecf20Sopenharmony_ci */ 85038c2ecf20Sopenharmony_civoid devlink_dpipe_headers_unregister(struct devlink *devlink) 85048c2ecf20Sopenharmony_ci{ 85058c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 85068c2ecf20Sopenharmony_ci devlink->dpipe_headers = NULL; 85078c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 85088c2ecf20Sopenharmony_ci} 85098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister); 85108c2ecf20Sopenharmony_ci 85118c2ecf20Sopenharmony_ci/** 85128c2ecf20Sopenharmony_ci * devlink_dpipe_table_counter_enabled - check if counter allocation 85138c2ecf20Sopenharmony_ci * required 85148c2ecf20Sopenharmony_ci * @devlink: devlink 85158c2ecf20Sopenharmony_ci * @table_name: tables name 85168c2ecf20Sopenharmony_ci * 85178c2ecf20Sopenharmony_ci * Used by driver to check if counter allocation is required. 85188c2ecf20Sopenharmony_ci * After counter allocation is turned on the table entries 85198c2ecf20Sopenharmony_ci * are updated to include counter statistics. 85208c2ecf20Sopenharmony_ci * 85218c2ecf20Sopenharmony_ci * After that point on the driver must respect the counter 85228c2ecf20Sopenharmony_ci * state so that each entry added to the table is added 85238c2ecf20Sopenharmony_ci * with a counter. 85248c2ecf20Sopenharmony_ci */ 85258c2ecf20Sopenharmony_cibool devlink_dpipe_table_counter_enabled(struct devlink *devlink, 85268c2ecf20Sopenharmony_ci const char *table_name) 85278c2ecf20Sopenharmony_ci{ 85288c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 85298c2ecf20Sopenharmony_ci bool enabled; 85308c2ecf20Sopenharmony_ci 85318c2ecf20Sopenharmony_ci rcu_read_lock(); 85328c2ecf20Sopenharmony_ci table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 85338c2ecf20Sopenharmony_ci table_name, devlink); 85348c2ecf20Sopenharmony_ci enabled = false; 85358c2ecf20Sopenharmony_ci if (table) 85368c2ecf20Sopenharmony_ci enabled = table->counters_enabled; 85378c2ecf20Sopenharmony_ci rcu_read_unlock(); 85388c2ecf20Sopenharmony_ci return enabled; 85398c2ecf20Sopenharmony_ci} 85408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled); 85418c2ecf20Sopenharmony_ci 85428c2ecf20Sopenharmony_ci/** 85438c2ecf20Sopenharmony_ci * devlink_dpipe_table_register - register dpipe table 85448c2ecf20Sopenharmony_ci * 85458c2ecf20Sopenharmony_ci * @devlink: devlink 85468c2ecf20Sopenharmony_ci * @table_name: table name 85478c2ecf20Sopenharmony_ci * @table_ops: table ops 85488c2ecf20Sopenharmony_ci * @priv: priv 85498c2ecf20Sopenharmony_ci * @counter_control_extern: external control for counters 85508c2ecf20Sopenharmony_ci */ 85518c2ecf20Sopenharmony_ciint devlink_dpipe_table_register(struct devlink *devlink, 85528c2ecf20Sopenharmony_ci const char *table_name, 85538c2ecf20Sopenharmony_ci struct devlink_dpipe_table_ops *table_ops, 85548c2ecf20Sopenharmony_ci void *priv, bool counter_control_extern) 85558c2ecf20Sopenharmony_ci{ 85568c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 85578c2ecf20Sopenharmony_ci int err = 0; 85588c2ecf20Sopenharmony_ci 85598c2ecf20Sopenharmony_ci if (WARN_ON(!table_ops->size_get)) 85608c2ecf20Sopenharmony_ci return -EINVAL; 85618c2ecf20Sopenharmony_ci 85628c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 85638c2ecf20Sopenharmony_ci 85648c2ecf20Sopenharmony_ci if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name, 85658c2ecf20Sopenharmony_ci devlink)) { 85668c2ecf20Sopenharmony_ci err = -EEXIST; 85678c2ecf20Sopenharmony_ci goto unlock; 85688c2ecf20Sopenharmony_ci } 85698c2ecf20Sopenharmony_ci 85708c2ecf20Sopenharmony_ci table = kzalloc(sizeof(*table), GFP_KERNEL); 85718c2ecf20Sopenharmony_ci if (!table) { 85728c2ecf20Sopenharmony_ci err = -ENOMEM; 85738c2ecf20Sopenharmony_ci goto unlock; 85748c2ecf20Sopenharmony_ci } 85758c2ecf20Sopenharmony_ci 85768c2ecf20Sopenharmony_ci table->name = table_name; 85778c2ecf20Sopenharmony_ci table->table_ops = table_ops; 85788c2ecf20Sopenharmony_ci table->priv = priv; 85798c2ecf20Sopenharmony_ci table->counter_control_extern = counter_control_extern; 85808c2ecf20Sopenharmony_ci 85818c2ecf20Sopenharmony_ci list_add_tail_rcu(&table->list, &devlink->dpipe_table_list); 85828c2ecf20Sopenharmony_ciunlock: 85838c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 85848c2ecf20Sopenharmony_ci return err; 85858c2ecf20Sopenharmony_ci} 85868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_register); 85878c2ecf20Sopenharmony_ci 85888c2ecf20Sopenharmony_ci/** 85898c2ecf20Sopenharmony_ci * devlink_dpipe_table_unregister - unregister dpipe table 85908c2ecf20Sopenharmony_ci * 85918c2ecf20Sopenharmony_ci * @devlink: devlink 85928c2ecf20Sopenharmony_ci * @table_name: table name 85938c2ecf20Sopenharmony_ci */ 85948c2ecf20Sopenharmony_civoid devlink_dpipe_table_unregister(struct devlink *devlink, 85958c2ecf20Sopenharmony_ci const char *table_name) 85968c2ecf20Sopenharmony_ci{ 85978c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 85988c2ecf20Sopenharmony_ci 85998c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 86008c2ecf20Sopenharmony_ci table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 86018c2ecf20Sopenharmony_ci table_name, devlink); 86028c2ecf20Sopenharmony_ci if (!table) 86038c2ecf20Sopenharmony_ci goto unlock; 86048c2ecf20Sopenharmony_ci list_del_rcu(&table->list); 86058c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 86068c2ecf20Sopenharmony_ci kfree_rcu(table, rcu); 86078c2ecf20Sopenharmony_ci return; 86088c2ecf20Sopenharmony_ciunlock: 86098c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 86108c2ecf20Sopenharmony_ci} 86118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); 86128c2ecf20Sopenharmony_ci 86138c2ecf20Sopenharmony_ci/** 86148c2ecf20Sopenharmony_ci * devlink_resource_register - devlink resource register 86158c2ecf20Sopenharmony_ci * 86168c2ecf20Sopenharmony_ci * @devlink: devlink 86178c2ecf20Sopenharmony_ci * @resource_name: resource's name 86188c2ecf20Sopenharmony_ci * @resource_size: resource's size 86198c2ecf20Sopenharmony_ci * @resource_id: resource's id 86208c2ecf20Sopenharmony_ci * @parent_resource_id: resource's parent id 86218c2ecf20Sopenharmony_ci * @size_params: size parameters 86228c2ecf20Sopenharmony_ci */ 86238c2ecf20Sopenharmony_ciint devlink_resource_register(struct devlink *devlink, 86248c2ecf20Sopenharmony_ci const char *resource_name, 86258c2ecf20Sopenharmony_ci u64 resource_size, 86268c2ecf20Sopenharmony_ci u64 resource_id, 86278c2ecf20Sopenharmony_ci u64 parent_resource_id, 86288c2ecf20Sopenharmony_ci const struct devlink_resource_size_params *size_params) 86298c2ecf20Sopenharmony_ci{ 86308c2ecf20Sopenharmony_ci struct devlink_resource *resource; 86318c2ecf20Sopenharmony_ci struct list_head *resource_list; 86328c2ecf20Sopenharmony_ci bool top_hierarchy; 86338c2ecf20Sopenharmony_ci int err = 0; 86348c2ecf20Sopenharmony_ci 86358c2ecf20Sopenharmony_ci top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP; 86368c2ecf20Sopenharmony_ci 86378c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 86388c2ecf20Sopenharmony_ci resource = devlink_resource_find(devlink, NULL, resource_id); 86398c2ecf20Sopenharmony_ci if (resource) { 86408c2ecf20Sopenharmony_ci err = -EINVAL; 86418c2ecf20Sopenharmony_ci goto out; 86428c2ecf20Sopenharmony_ci } 86438c2ecf20Sopenharmony_ci 86448c2ecf20Sopenharmony_ci resource = kzalloc(sizeof(*resource), GFP_KERNEL); 86458c2ecf20Sopenharmony_ci if (!resource) { 86468c2ecf20Sopenharmony_ci err = -ENOMEM; 86478c2ecf20Sopenharmony_ci goto out; 86488c2ecf20Sopenharmony_ci } 86498c2ecf20Sopenharmony_ci 86508c2ecf20Sopenharmony_ci if (top_hierarchy) { 86518c2ecf20Sopenharmony_ci resource_list = &devlink->resource_list; 86528c2ecf20Sopenharmony_ci } else { 86538c2ecf20Sopenharmony_ci struct devlink_resource *parent_resource; 86548c2ecf20Sopenharmony_ci 86558c2ecf20Sopenharmony_ci parent_resource = devlink_resource_find(devlink, NULL, 86568c2ecf20Sopenharmony_ci parent_resource_id); 86578c2ecf20Sopenharmony_ci if (parent_resource) { 86588c2ecf20Sopenharmony_ci resource_list = &parent_resource->resource_list; 86598c2ecf20Sopenharmony_ci resource->parent = parent_resource; 86608c2ecf20Sopenharmony_ci } else { 86618c2ecf20Sopenharmony_ci kfree(resource); 86628c2ecf20Sopenharmony_ci err = -EINVAL; 86638c2ecf20Sopenharmony_ci goto out; 86648c2ecf20Sopenharmony_ci } 86658c2ecf20Sopenharmony_ci } 86668c2ecf20Sopenharmony_ci 86678c2ecf20Sopenharmony_ci resource->name = resource_name; 86688c2ecf20Sopenharmony_ci resource->size = resource_size; 86698c2ecf20Sopenharmony_ci resource->size_new = resource_size; 86708c2ecf20Sopenharmony_ci resource->id = resource_id; 86718c2ecf20Sopenharmony_ci resource->size_valid = true; 86728c2ecf20Sopenharmony_ci memcpy(&resource->size_params, size_params, 86738c2ecf20Sopenharmony_ci sizeof(resource->size_params)); 86748c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&resource->resource_list); 86758c2ecf20Sopenharmony_ci list_add_tail(&resource->list, resource_list); 86768c2ecf20Sopenharmony_ciout: 86778c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 86788c2ecf20Sopenharmony_ci return err; 86798c2ecf20Sopenharmony_ci} 86808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_register); 86818c2ecf20Sopenharmony_ci 86828c2ecf20Sopenharmony_ci/** 86838c2ecf20Sopenharmony_ci * devlink_resources_unregister - free all resources 86848c2ecf20Sopenharmony_ci * 86858c2ecf20Sopenharmony_ci * @devlink: devlink 86868c2ecf20Sopenharmony_ci * @resource: resource 86878c2ecf20Sopenharmony_ci */ 86888c2ecf20Sopenharmony_civoid devlink_resources_unregister(struct devlink *devlink, 86898c2ecf20Sopenharmony_ci struct devlink_resource *resource) 86908c2ecf20Sopenharmony_ci{ 86918c2ecf20Sopenharmony_ci struct devlink_resource *tmp, *child_resource; 86928c2ecf20Sopenharmony_ci struct list_head *resource_list; 86938c2ecf20Sopenharmony_ci 86948c2ecf20Sopenharmony_ci if (resource) 86958c2ecf20Sopenharmony_ci resource_list = &resource->resource_list; 86968c2ecf20Sopenharmony_ci else 86978c2ecf20Sopenharmony_ci resource_list = &devlink->resource_list; 86988c2ecf20Sopenharmony_ci 86998c2ecf20Sopenharmony_ci if (!resource) 87008c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 87018c2ecf20Sopenharmony_ci 87028c2ecf20Sopenharmony_ci list_for_each_entry_safe(child_resource, tmp, resource_list, list) { 87038c2ecf20Sopenharmony_ci devlink_resources_unregister(devlink, child_resource); 87048c2ecf20Sopenharmony_ci list_del(&child_resource->list); 87058c2ecf20Sopenharmony_ci kfree(child_resource); 87068c2ecf20Sopenharmony_ci } 87078c2ecf20Sopenharmony_ci 87088c2ecf20Sopenharmony_ci if (!resource) 87098c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 87108c2ecf20Sopenharmony_ci} 87118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resources_unregister); 87128c2ecf20Sopenharmony_ci 87138c2ecf20Sopenharmony_ci/** 87148c2ecf20Sopenharmony_ci * devlink_resource_size_get - get and update size 87158c2ecf20Sopenharmony_ci * 87168c2ecf20Sopenharmony_ci * @devlink: devlink 87178c2ecf20Sopenharmony_ci * @resource_id: the requested resource id 87188c2ecf20Sopenharmony_ci * @p_resource_size: ptr to update 87198c2ecf20Sopenharmony_ci */ 87208c2ecf20Sopenharmony_ciint devlink_resource_size_get(struct devlink *devlink, 87218c2ecf20Sopenharmony_ci u64 resource_id, 87228c2ecf20Sopenharmony_ci u64 *p_resource_size) 87238c2ecf20Sopenharmony_ci{ 87248c2ecf20Sopenharmony_ci struct devlink_resource *resource; 87258c2ecf20Sopenharmony_ci int err = 0; 87268c2ecf20Sopenharmony_ci 87278c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 87288c2ecf20Sopenharmony_ci resource = devlink_resource_find(devlink, NULL, resource_id); 87298c2ecf20Sopenharmony_ci if (!resource) { 87308c2ecf20Sopenharmony_ci err = -EINVAL; 87318c2ecf20Sopenharmony_ci goto out; 87328c2ecf20Sopenharmony_ci } 87338c2ecf20Sopenharmony_ci *p_resource_size = resource->size_new; 87348c2ecf20Sopenharmony_ci resource->size = resource->size_new; 87358c2ecf20Sopenharmony_ciout: 87368c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 87378c2ecf20Sopenharmony_ci return err; 87388c2ecf20Sopenharmony_ci} 87398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_size_get); 87408c2ecf20Sopenharmony_ci 87418c2ecf20Sopenharmony_ci/** 87428c2ecf20Sopenharmony_ci * devlink_dpipe_table_resource_set - set the resource id 87438c2ecf20Sopenharmony_ci * 87448c2ecf20Sopenharmony_ci * @devlink: devlink 87458c2ecf20Sopenharmony_ci * @table_name: table name 87468c2ecf20Sopenharmony_ci * @resource_id: resource id 87478c2ecf20Sopenharmony_ci * @resource_units: number of resource's units consumed per table's entry 87488c2ecf20Sopenharmony_ci */ 87498c2ecf20Sopenharmony_ciint devlink_dpipe_table_resource_set(struct devlink *devlink, 87508c2ecf20Sopenharmony_ci const char *table_name, u64 resource_id, 87518c2ecf20Sopenharmony_ci u64 resource_units) 87528c2ecf20Sopenharmony_ci{ 87538c2ecf20Sopenharmony_ci struct devlink_dpipe_table *table; 87548c2ecf20Sopenharmony_ci int err = 0; 87558c2ecf20Sopenharmony_ci 87568c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 87578c2ecf20Sopenharmony_ci table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 87588c2ecf20Sopenharmony_ci table_name, devlink); 87598c2ecf20Sopenharmony_ci if (!table) { 87608c2ecf20Sopenharmony_ci err = -EINVAL; 87618c2ecf20Sopenharmony_ci goto out; 87628c2ecf20Sopenharmony_ci } 87638c2ecf20Sopenharmony_ci table->resource_id = resource_id; 87648c2ecf20Sopenharmony_ci table->resource_units = resource_units; 87658c2ecf20Sopenharmony_ci table->resource_valid = true; 87668c2ecf20Sopenharmony_ciout: 87678c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 87688c2ecf20Sopenharmony_ci return err; 87698c2ecf20Sopenharmony_ci} 87708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set); 87718c2ecf20Sopenharmony_ci 87728c2ecf20Sopenharmony_ci/** 87738c2ecf20Sopenharmony_ci * devlink_resource_occ_get_register - register occupancy getter 87748c2ecf20Sopenharmony_ci * 87758c2ecf20Sopenharmony_ci * @devlink: devlink 87768c2ecf20Sopenharmony_ci * @resource_id: resource id 87778c2ecf20Sopenharmony_ci * @occ_get: occupancy getter callback 87788c2ecf20Sopenharmony_ci * @occ_get_priv: occupancy getter callback priv 87798c2ecf20Sopenharmony_ci */ 87808c2ecf20Sopenharmony_civoid devlink_resource_occ_get_register(struct devlink *devlink, 87818c2ecf20Sopenharmony_ci u64 resource_id, 87828c2ecf20Sopenharmony_ci devlink_resource_occ_get_t *occ_get, 87838c2ecf20Sopenharmony_ci void *occ_get_priv) 87848c2ecf20Sopenharmony_ci{ 87858c2ecf20Sopenharmony_ci struct devlink_resource *resource; 87868c2ecf20Sopenharmony_ci 87878c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 87888c2ecf20Sopenharmony_ci resource = devlink_resource_find(devlink, NULL, resource_id); 87898c2ecf20Sopenharmony_ci if (WARN_ON(!resource)) 87908c2ecf20Sopenharmony_ci goto out; 87918c2ecf20Sopenharmony_ci WARN_ON(resource->occ_get); 87928c2ecf20Sopenharmony_ci 87938c2ecf20Sopenharmony_ci resource->occ_get = occ_get; 87948c2ecf20Sopenharmony_ci resource->occ_get_priv = occ_get_priv; 87958c2ecf20Sopenharmony_ciout: 87968c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 87978c2ecf20Sopenharmony_ci} 87988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_occ_get_register); 87998c2ecf20Sopenharmony_ci 88008c2ecf20Sopenharmony_ci/** 88018c2ecf20Sopenharmony_ci * devlink_resource_occ_get_unregister - unregister occupancy getter 88028c2ecf20Sopenharmony_ci * 88038c2ecf20Sopenharmony_ci * @devlink: devlink 88048c2ecf20Sopenharmony_ci * @resource_id: resource id 88058c2ecf20Sopenharmony_ci */ 88068c2ecf20Sopenharmony_civoid devlink_resource_occ_get_unregister(struct devlink *devlink, 88078c2ecf20Sopenharmony_ci u64 resource_id) 88088c2ecf20Sopenharmony_ci{ 88098c2ecf20Sopenharmony_ci struct devlink_resource *resource; 88108c2ecf20Sopenharmony_ci 88118c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 88128c2ecf20Sopenharmony_ci resource = devlink_resource_find(devlink, NULL, resource_id); 88138c2ecf20Sopenharmony_ci if (WARN_ON(!resource)) 88148c2ecf20Sopenharmony_ci goto out; 88158c2ecf20Sopenharmony_ci WARN_ON(!resource->occ_get); 88168c2ecf20Sopenharmony_ci 88178c2ecf20Sopenharmony_ci resource->occ_get = NULL; 88188c2ecf20Sopenharmony_ci resource->occ_get_priv = NULL; 88198c2ecf20Sopenharmony_ciout: 88208c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 88218c2ecf20Sopenharmony_ci} 88228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister); 88238c2ecf20Sopenharmony_ci 88248c2ecf20Sopenharmony_cistatic int devlink_param_verify(const struct devlink_param *param) 88258c2ecf20Sopenharmony_ci{ 88268c2ecf20Sopenharmony_ci if (!param || !param->name || !param->supported_cmodes) 88278c2ecf20Sopenharmony_ci return -EINVAL; 88288c2ecf20Sopenharmony_ci if (param->generic) 88298c2ecf20Sopenharmony_ci return devlink_param_generic_verify(param); 88308c2ecf20Sopenharmony_ci else 88318c2ecf20Sopenharmony_ci return devlink_param_driver_verify(param); 88328c2ecf20Sopenharmony_ci} 88338c2ecf20Sopenharmony_ci 88348c2ecf20Sopenharmony_cistatic int __devlink_params_register(struct devlink *devlink, 88358c2ecf20Sopenharmony_ci unsigned int port_index, 88368c2ecf20Sopenharmony_ci struct list_head *param_list, 88378c2ecf20Sopenharmony_ci const struct devlink_param *params, 88388c2ecf20Sopenharmony_ci size_t params_count, 88398c2ecf20Sopenharmony_ci enum devlink_command reg_cmd, 88408c2ecf20Sopenharmony_ci enum devlink_command unreg_cmd) 88418c2ecf20Sopenharmony_ci{ 88428c2ecf20Sopenharmony_ci const struct devlink_param *param = params; 88438c2ecf20Sopenharmony_ci int i; 88448c2ecf20Sopenharmony_ci int err; 88458c2ecf20Sopenharmony_ci 88468c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 88478c2ecf20Sopenharmony_ci for (i = 0; i < params_count; i++, param++) { 88488c2ecf20Sopenharmony_ci err = devlink_param_verify(param); 88498c2ecf20Sopenharmony_ci if (err) 88508c2ecf20Sopenharmony_ci goto rollback; 88518c2ecf20Sopenharmony_ci 88528c2ecf20Sopenharmony_ci err = devlink_param_register_one(devlink, port_index, 88538c2ecf20Sopenharmony_ci param_list, param, reg_cmd); 88548c2ecf20Sopenharmony_ci if (err) 88558c2ecf20Sopenharmony_ci goto rollback; 88568c2ecf20Sopenharmony_ci } 88578c2ecf20Sopenharmony_ci 88588c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 88598c2ecf20Sopenharmony_ci return 0; 88608c2ecf20Sopenharmony_ci 88618c2ecf20Sopenharmony_cirollback: 88628c2ecf20Sopenharmony_ci if (!i) 88638c2ecf20Sopenharmony_ci goto unlock; 88648c2ecf20Sopenharmony_ci for (param--; i > 0; i--, param--) 88658c2ecf20Sopenharmony_ci devlink_param_unregister_one(devlink, port_index, param_list, 88668c2ecf20Sopenharmony_ci param, unreg_cmd); 88678c2ecf20Sopenharmony_ciunlock: 88688c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 88698c2ecf20Sopenharmony_ci return err; 88708c2ecf20Sopenharmony_ci} 88718c2ecf20Sopenharmony_ci 88728c2ecf20Sopenharmony_cistatic void __devlink_params_unregister(struct devlink *devlink, 88738c2ecf20Sopenharmony_ci unsigned int port_index, 88748c2ecf20Sopenharmony_ci struct list_head *param_list, 88758c2ecf20Sopenharmony_ci const struct devlink_param *params, 88768c2ecf20Sopenharmony_ci size_t params_count, 88778c2ecf20Sopenharmony_ci enum devlink_command cmd) 88788c2ecf20Sopenharmony_ci{ 88798c2ecf20Sopenharmony_ci const struct devlink_param *param = params; 88808c2ecf20Sopenharmony_ci int i; 88818c2ecf20Sopenharmony_ci 88828c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 88838c2ecf20Sopenharmony_ci for (i = 0; i < params_count; i++, param++) 88848c2ecf20Sopenharmony_ci devlink_param_unregister_one(devlink, 0, param_list, param, 88858c2ecf20Sopenharmony_ci cmd); 88868c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 88878c2ecf20Sopenharmony_ci} 88888c2ecf20Sopenharmony_ci 88898c2ecf20Sopenharmony_ci/** 88908c2ecf20Sopenharmony_ci * devlink_params_register - register configuration parameters 88918c2ecf20Sopenharmony_ci * 88928c2ecf20Sopenharmony_ci * @devlink: devlink 88938c2ecf20Sopenharmony_ci * @params: configuration parameters array 88948c2ecf20Sopenharmony_ci * @params_count: number of parameters provided 88958c2ecf20Sopenharmony_ci * 88968c2ecf20Sopenharmony_ci * Register the configuration parameters supported by the driver. 88978c2ecf20Sopenharmony_ci */ 88988c2ecf20Sopenharmony_ciint devlink_params_register(struct devlink *devlink, 88998c2ecf20Sopenharmony_ci const struct devlink_param *params, 89008c2ecf20Sopenharmony_ci size_t params_count) 89018c2ecf20Sopenharmony_ci{ 89028c2ecf20Sopenharmony_ci return __devlink_params_register(devlink, 0, &devlink->param_list, 89038c2ecf20Sopenharmony_ci params, params_count, 89048c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_NEW, 89058c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_DEL); 89068c2ecf20Sopenharmony_ci} 89078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_register); 89088c2ecf20Sopenharmony_ci 89098c2ecf20Sopenharmony_ci/** 89108c2ecf20Sopenharmony_ci * devlink_params_unregister - unregister configuration parameters 89118c2ecf20Sopenharmony_ci * @devlink: devlink 89128c2ecf20Sopenharmony_ci * @params: configuration parameters to unregister 89138c2ecf20Sopenharmony_ci * @params_count: number of parameters provided 89148c2ecf20Sopenharmony_ci */ 89158c2ecf20Sopenharmony_civoid devlink_params_unregister(struct devlink *devlink, 89168c2ecf20Sopenharmony_ci const struct devlink_param *params, 89178c2ecf20Sopenharmony_ci size_t params_count) 89188c2ecf20Sopenharmony_ci{ 89198c2ecf20Sopenharmony_ci return __devlink_params_unregister(devlink, 0, &devlink->param_list, 89208c2ecf20Sopenharmony_ci params, params_count, 89218c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_DEL); 89228c2ecf20Sopenharmony_ci} 89238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_unregister); 89248c2ecf20Sopenharmony_ci 89258c2ecf20Sopenharmony_ci/** 89268c2ecf20Sopenharmony_ci * devlink_params_publish - publish configuration parameters 89278c2ecf20Sopenharmony_ci * 89288c2ecf20Sopenharmony_ci * @devlink: devlink 89298c2ecf20Sopenharmony_ci * 89308c2ecf20Sopenharmony_ci * Publish previously registered configuration parameters. 89318c2ecf20Sopenharmony_ci */ 89328c2ecf20Sopenharmony_civoid devlink_params_publish(struct devlink *devlink) 89338c2ecf20Sopenharmony_ci{ 89348c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 89358c2ecf20Sopenharmony_ci 89368c2ecf20Sopenharmony_ci list_for_each_entry(param_item, &devlink->param_list, list) { 89378c2ecf20Sopenharmony_ci if (param_item->published) 89388c2ecf20Sopenharmony_ci continue; 89398c2ecf20Sopenharmony_ci param_item->published = true; 89408c2ecf20Sopenharmony_ci devlink_param_notify(devlink, 0, param_item, 89418c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_NEW); 89428c2ecf20Sopenharmony_ci } 89438c2ecf20Sopenharmony_ci} 89448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_publish); 89458c2ecf20Sopenharmony_ci 89468c2ecf20Sopenharmony_ci/** 89478c2ecf20Sopenharmony_ci * devlink_params_unpublish - unpublish configuration parameters 89488c2ecf20Sopenharmony_ci * 89498c2ecf20Sopenharmony_ci * @devlink: devlink 89508c2ecf20Sopenharmony_ci * 89518c2ecf20Sopenharmony_ci * Unpublish previously registered configuration parameters. 89528c2ecf20Sopenharmony_ci */ 89538c2ecf20Sopenharmony_civoid devlink_params_unpublish(struct devlink *devlink) 89548c2ecf20Sopenharmony_ci{ 89558c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 89568c2ecf20Sopenharmony_ci 89578c2ecf20Sopenharmony_ci list_for_each_entry(param_item, &devlink->param_list, list) { 89588c2ecf20Sopenharmony_ci if (!param_item->published) 89598c2ecf20Sopenharmony_ci continue; 89608c2ecf20Sopenharmony_ci param_item->published = false; 89618c2ecf20Sopenharmony_ci devlink_param_notify(devlink, 0, param_item, 89628c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_DEL); 89638c2ecf20Sopenharmony_ci } 89648c2ecf20Sopenharmony_ci} 89658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_unpublish); 89668c2ecf20Sopenharmony_ci 89678c2ecf20Sopenharmony_ci/** 89688c2ecf20Sopenharmony_ci * devlink_port_params_register - register port configuration parameters 89698c2ecf20Sopenharmony_ci * 89708c2ecf20Sopenharmony_ci * @devlink_port: devlink port 89718c2ecf20Sopenharmony_ci * @params: configuration parameters array 89728c2ecf20Sopenharmony_ci * @params_count: number of parameters provided 89738c2ecf20Sopenharmony_ci * 89748c2ecf20Sopenharmony_ci * Register the configuration parameters supported by the port. 89758c2ecf20Sopenharmony_ci */ 89768c2ecf20Sopenharmony_ciint devlink_port_params_register(struct devlink_port *devlink_port, 89778c2ecf20Sopenharmony_ci const struct devlink_param *params, 89788c2ecf20Sopenharmony_ci size_t params_count) 89798c2ecf20Sopenharmony_ci{ 89808c2ecf20Sopenharmony_ci return __devlink_params_register(devlink_port->devlink, 89818c2ecf20Sopenharmony_ci devlink_port->index, 89828c2ecf20Sopenharmony_ci &devlink_port->param_list, params, 89838c2ecf20Sopenharmony_ci params_count, 89848c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_NEW, 89858c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_DEL); 89868c2ecf20Sopenharmony_ci} 89878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_params_register); 89888c2ecf20Sopenharmony_ci 89898c2ecf20Sopenharmony_ci/** 89908c2ecf20Sopenharmony_ci * devlink_port_params_unregister - unregister port configuration 89918c2ecf20Sopenharmony_ci * parameters 89928c2ecf20Sopenharmony_ci * 89938c2ecf20Sopenharmony_ci * @devlink_port: devlink port 89948c2ecf20Sopenharmony_ci * @params: configuration parameters array 89958c2ecf20Sopenharmony_ci * @params_count: number of parameters provided 89968c2ecf20Sopenharmony_ci */ 89978c2ecf20Sopenharmony_civoid devlink_port_params_unregister(struct devlink_port *devlink_port, 89988c2ecf20Sopenharmony_ci const struct devlink_param *params, 89998c2ecf20Sopenharmony_ci size_t params_count) 90008c2ecf20Sopenharmony_ci{ 90018c2ecf20Sopenharmony_ci return __devlink_params_unregister(devlink_port->devlink, 90028c2ecf20Sopenharmony_ci devlink_port->index, 90038c2ecf20Sopenharmony_ci &devlink_port->param_list, 90048c2ecf20Sopenharmony_ci params, params_count, 90058c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_DEL); 90068c2ecf20Sopenharmony_ci} 90078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_params_unregister); 90088c2ecf20Sopenharmony_ci 90098c2ecf20Sopenharmony_cistatic int 90108c2ecf20Sopenharmony_ci__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id, 90118c2ecf20Sopenharmony_ci union devlink_param_value *init_val) 90128c2ecf20Sopenharmony_ci{ 90138c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 90148c2ecf20Sopenharmony_ci 90158c2ecf20Sopenharmony_ci param_item = devlink_param_find_by_id(param_list, param_id); 90168c2ecf20Sopenharmony_ci if (!param_item) 90178c2ecf20Sopenharmony_ci return -EINVAL; 90188c2ecf20Sopenharmony_ci 90198c2ecf20Sopenharmony_ci if (!param_item->driverinit_value_valid || 90208c2ecf20Sopenharmony_ci !devlink_param_cmode_is_supported(param_item->param, 90218c2ecf20Sopenharmony_ci DEVLINK_PARAM_CMODE_DRIVERINIT)) 90228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 90238c2ecf20Sopenharmony_ci 90248c2ecf20Sopenharmony_ci if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING) 90258c2ecf20Sopenharmony_ci strcpy(init_val->vstr, param_item->driverinit_value.vstr); 90268c2ecf20Sopenharmony_ci else 90278c2ecf20Sopenharmony_ci *init_val = param_item->driverinit_value; 90288c2ecf20Sopenharmony_ci 90298c2ecf20Sopenharmony_ci return 0; 90308c2ecf20Sopenharmony_ci} 90318c2ecf20Sopenharmony_ci 90328c2ecf20Sopenharmony_cistatic int 90338c2ecf20Sopenharmony_ci__devlink_param_driverinit_value_set(struct devlink *devlink, 90348c2ecf20Sopenharmony_ci unsigned int port_index, 90358c2ecf20Sopenharmony_ci struct list_head *param_list, u32 param_id, 90368c2ecf20Sopenharmony_ci union devlink_param_value init_val, 90378c2ecf20Sopenharmony_ci enum devlink_command cmd) 90388c2ecf20Sopenharmony_ci{ 90398c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 90408c2ecf20Sopenharmony_ci 90418c2ecf20Sopenharmony_ci param_item = devlink_param_find_by_id(param_list, param_id); 90428c2ecf20Sopenharmony_ci if (!param_item) 90438c2ecf20Sopenharmony_ci return -EINVAL; 90448c2ecf20Sopenharmony_ci 90458c2ecf20Sopenharmony_ci if (!devlink_param_cmode_is_supported(param_item->param, 90468c2ecf20Sopenharmony_ci DEVLINK_PARAM_CMODE_DRIVERINIT)) 90478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 90488c2ecf20Sopenharmony_ci 90498c2ecf20Sopenharmony_ci if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING) 90508c2ecf20Sopenharmony_ci strcpy(param_item->driverinit_value.vstr, init_val.vstr); 90518c2ecf20Sopenharmony_ci else 90528c2ecf20Sopenharmony_ci param_item->driverinit_value = init_val; 90538c2ecf20Sopenharmony_ci param_item->driverinit_value_valid = true; 90548c2ecf20Sopenharmony_ci 90558c2ecf20Sopenharmony_ci devlink_param_notify(devlink, port_index, param_item, cmd); 90568c2ecf20Sopenharmony_ci return 0; 90578c2ecf20Sopenharmony_ci} 90588c2ecf20Sopenharmony_ci 90598c2ecf20Sopenharmony_ci/** 90608c2ecf20Sopenharmony_ci * devlink_param_driverinit_value_get - get configuration parameter 90618c2ecf20Sopenharmony_ci * value for driver initializing 90628c2ecf20Sopenharmony_ci * 90638c2ecf20Sopenharmony_ci * @devlink: devlink 90648c2ecf20Sopenharmony_ci * @param_id: parameter ID 90658c2ecf20Sopenharmony_ci * @init_val: value of parameter in driverinit configuration mode 90668c2ecf20Sopenharmony_ci * 90678c2ecf20Sopenharmony_ci * This function should be used by the driver to get driverinit 90688c2ecf20Sopenharmony_ci * configuration for initialization after reload command. 90698c2ecf20Sopenharmony_ci */ 90708c2ecf20Sopenharmony_ciint devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id, 90718c2ecf20Sopenharmony_ci union devlink_param_value *init_val) 90728c2ecf20Sopenharmony_ci{ 90738c2ecf20Sopenharmony_ci if (!devlink_reload_supported(devlink->ops)) 90748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 90758c2ecf20Sopenharmony_ci 90768c2ecf20Sopenharmony_ci return __devlink_param_driverinit_value_get(&devlink->param_list, 90778c2ecf20Sopenharmony_ci param_id, init_val); 90788c2ecf20Sopenharmony_ci} 90798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get); 90808c2ecf20Sopenharmony_ci 90818c2ecf20Sopenharmony_ci/** 90828c2ecf20Sopenharmony_ci * devlink_param_driverinit_value_set - set value of configuration 90838c2ecf20Sopenharmony_ci * parameter for driverinit 90848c2ecf20Sopenharmony_ci * configuration mode 90858c2ecf20Sopenharmony_ci * 90868c2ecf20Sopenharmony_ci * @devlink: devlink 90878c2ecf20Sopenharmony_ci * @param_id: parameter ID 90888c2ecf20Sopenharmony_ci * @init_val: value of parameter to set for driverinit configuration mode 90898c2ecf20Sopenharmony_ci * 90908c2ecf20Sopenharmony_ci * This function should be used by the driver to set driverinit 90918c2ecf20Sopenharmony_ci * configuration mode default value. 90928c2ecf20Sopenharmony_ci */ 90938c2ecf20Sopenharmony_ciint devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id, 90948c2ecf20Sopenharmony_ci union devlink_param_value init_val) 90958c2ecf20Sopenharmony_ci{ 90968c2ecf20Sopenharmony_ci return __devlink_param_driverinit_value_set(devlink, 0, 90978c2ecf20Sopenharmony_ci &devlink->param_list, 90988c2ecf20Sopenharmony_ci param_id, init_val, 90998c2ecf20Sopenharmony_ci DEVLINK_CMD_PARAM_NEW); 91008c2ecf20Sopenharmony_ci} 91018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set); 91028c2ecf20Sopenharmony_ci 91038c2ecf20Sopenharmony_ci/** 91048c2ecf20Sopenharmony_ci * devlink_port_param_driverinit_value_get - get configuration parameter 91058c2ecf20Sopenharmony_ci * value for driver initializing 91068c2ecf20Sopenharmony_ci * 91078c2ecf20Sopenharmony_ci * @devlink_port: devlink_port 91088c2ecf20Sopenharmony_ci * @param_id: parameter ID 91098c2ecf20Sopenharmony_ci * @init_val: value of parameter in driverinit configuration mode 91108c2ecf20Sopenharmony_ci * 91118c2ecf20Sopenharmony_ci * This function should be used by the driver to get driverinit 91128c2ecf20Sopenharmony_ci * configuration for initialization after reload command. 91138c2ecf20Sopenharmony_ci */ 91148c2ecf20Sopenharmony_ciint devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port, 91158c2ecf20Sopenharmony_ci u32 param_id, 91168c2ecf20Sopenharmony_ci union devlink_param_value *init_val) 91178c2ecf20Sopenharmony_ci{ 91188c2ecf20Sopenharmony_ci struct devlink *devlink = devlink_port->devlink; 91198c2ecf20Sopenharmony_ci 91208c2ecf20Sopenharmony_ci if (!devlink_reload_supported(devlink->ops)) 91218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 91228c2ecf20Sopenharmony_ci 91238c2ecf20Sopenharmony_ci return __devlink_param_driverinit_value_get(&devlink_port->param_list, 91248c2ecf20Sopenharmony_ci param_id, init_val); 91258c2ecf20Sopenharmony_ci} 91268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get); 91278c2ecf20Sopenharmony_ci 91288c2ecf20Sopenharmony_ci/** 91298c2ecf20Sopenharmony_ci * devlink_port_param_driverinit_value_set - set value of configuration 91308c2ecf20Sopenharmony_ci * parameter for driverinit 91318c2ecf20Sopenharmony_ci * configuration mode 91328c2ecf20Sopenharmony_ci * 91338c2ecf20Sopenharmony_ci * @devlink_port: devlink_port 91348c2ecf20Sopenharmony_ci * @param_id: parameter ID 91358c2ecf20Sopenharmony_ci * @init_val: value of parameter to set for driverinit configuration mode 91368c2ecf20Sopenharmony_ci * 91378c2ecf20Sopenharmony_ci * This function should be used by the driver to set driverinit 91388c2ecf20Sopenharmony_ci * configuration mode default value. 91398c2ecf20Sopenharmony_ci */ 91408c2ecf20Sopenharmony_ciint devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port, 91418c2ecf20Sopenharmony_ci u32 param_id, 91428c2ecf20Sopenharmony_ci union devlink_param_value init_val) 91438c2ecf20Sopenharmony_ci{ 91448c2ecf20Sopenharmony_ci return __devlink_param_driverinit_value_set(devlink_port->devlink, 91458c2ecf20Sopenharmony_ci devlink_port->index, 91468c2ecf20Sopenharmony_ci &devlink_port->param_list, 91478c2ecf20Sopenharmony_ci param_id, init_val, 91488c2ecf20Sopenharmony_ci DEVLINK_CMD_PORT_PARAM_NEW); 91498c2ecf20Sopenharmony_ci} 91508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set); 91518c2ecf20Sopenharmony_ci 91528c2ecf20Sopenharmony_ci/** 91538c2ecf20Sopenharmony_ci * devlink_param_value_changed - notify devlink on a parameter's value 91548c2ecf20Sopenharmony_ci * change. Should be called by the driver 91558c2ecf20Sopenharmony_ci * right after the change. 91568c2ecf20Sopenharmony_ci * 91578c2ecf20Sopenharmony_ci * @devlink: devlink 91588c2ecf20Sopenharmony_ci * @param_id: parameter ID 91598c2ecf20Sopenharmony_ci * 91608c2ecf20Sopenharmony_ci * This function should be used by the driver to notify devlink on value 91618c2ecf20Sopenharmony_ci * change, excluding driverinit configuration mode. 91628c2ecf20Sopenharmony_ci * For driverinit configuration mode driver should use the function 91638c2ecf20Sopenharmony_ci */ 91648c2ecf20Sopenharmony_civoid devlink_param_value_changed(struct devlink *devlink, u32 param_id) 91658c2ecf20Sopenharmony_ci{ 91668c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 91678c2ecf20Sopenharmony_ci 91688c2ecf20Sopenharmony_ci param_item = devlink_param_find_by_id(&devlink->param_list, param_id); 91698c2ecf20Sopenharmony_ci WARN_ON(!param_item); 91708c2ecf20Sopenharmony_ci 91718c2ecf20Sopenharmony_ci devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW); 91728c2ecf20Sopenharmony_ci} 91738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_value_changed); 91748c2ecf20Sopenharmony_ci 91758c2ecf20Sopenharmony_ci/** 91768c2ecf20Sopenharmony_ci * devlink_port_param_value_changed - notify devlink on a parameter's value 91778c2ecf20Sopenharmony_ci * change. Should be called by the driver 91788c2ecf20Sopenharmony_ci * right after the change. 91798c2ecf20Sopenharmony_ci * 91808c2ecf20Sopenharmony_ci * @devlink_port: devlink_port 91818c2ecf20Sopenharmony_ci * @param_id: parameter ID 91828c2ecf20Sopenharmony_ci * 91838c2ecf20Sopenharmony_ci * This function should be used by the driver to notify devlink on value 91848c2ecf20Sopenharmony_ci * change, excluding driverinit configuration mode. 91858c2ecf20Sopenharmony_ci * For driverinit configuration mode driver should use the function 91868c2ecf20Sopenharmony_ci * devlink_port_param_driverinit_value_set() instead. 91878c2ecf20Sopenharmony_ci */ 91888c2ecf20Sopenharmony_civoid devlink_port_param_value_changed(struct devlink_port *devlink_port, 91898c2ecf20Sopenharmony_ci u32 param_id) 91908c2ecf20Sopenharmony_ci{ 91918c2ecf20Sopenharmony_ci struct devlink_param_item *param_item; 91928c2ecf20Sopenharmony_ci 91938c2ecf20Sopenharmony_ci param_item = devlink_param_find_by_id(&devlink_port->param_list, 91948c2ecf20Sopenharmony_ci param_id); 91958c2ecf20Sopenharmony_ci WARN_ON(!param_item); 91968c2ecf20Sopenharmony_ci 91978c2ecf20Sopenharmony_ci devlink_param_notify(devlink_port->devlink, devlink_port->index, 91988c2ecf20Sopenharmony_ci param_item, DEVLINK_CMD_PORT_PARAM_NEW); 91998c2ecf20Sopenharmony_ci} 92008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_value_changed); 92018c2ecf20Sopenharmony_ci 92028c2ecf20Sopenharmony_ci/** 92038c2ecf20Sopenharmony_ci * devlink_param_value_str_fill - Safely fill-up the string preventing 92048c2ecf20Sopenharmony_ci * from overflow of the preallocated buffer 92058c2ecf20Sopenharmony_ci * 92068c2ecf20Sopenharmony_ci * @dst_val: destination devlink_param_value 92078c2ecf20Sopenharmony_ci * @src: source buffer 92088c2ecf20Sopenharmony_ci */ 92098c2ecf20Sopenharmony_civoid devlink_param_value_str_fill(union devlink_param_value *dst_val, 92108c2ecf20Sopenharmony_ci const char *src) 92118c2ecf20Sopenharmony_ci{ 92128c2ecf20Sopenharmony_ci size_t len; 92138c2ecf20Sopenharmony_ci 92148c2ecf20Sopenharmony_ci len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE); 92158c2ecf20Sopenharmony_ci WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE); 92168c2ecf20Sopenharmony_ci} 92178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_value_str_fill); 92188c2ecf20Sopenharmony_ci 92198c2ecf20Sopenharmony_ci/** 92208c2ecf20Sopenharmony_ci * devlink_region_create - create a new address region 92218c2ecf20Sopenharmony_ci * 92228c2ecf20Sopenharmony_ci * @devlink: devlink 92238c2ecf20Sopenharmony_ci * @ops: region operations and name 92248c2ecf20Sopenharmony_ci * @region_max_snapshots: Maximum supported number of snapshots for region 92258c2ecf20Sopenharmony_ci * @region_size: size of region 92268c2ecf20Sopenharmony_ci */ 92278c2ecf20Sopenharmony_cistruct devlink_region * 92288c2ecf20Sopenharmony_cidevlink_region_create(struct devlink *devlink, 92298c2ecf20Sopenharmony_ci const struct devlink_region_ops *ops, 92308c2ecf20Sopenharmony_ci u32 region_max_snapshots, u64 region_size) 92318c2ecf20Sopenharmony_ci{ 92328c2ecf20Sopenharmony_ci struct devlink_region *region; 92338c2ecf20Sopenharmony_ci int err = 0; 92348c2ecf20Sopenharmony_ci 92358c2ecf20Sopenharmony_ci if (WARN_ON(!ops) || WARN_ON(!ops->destructor)) 92368c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 92378c2ecf20Sopenharmony_ci 92388c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 92398c2ecf20Sopenharmony_ci 92408c2ecf20Sopenharmony_ci if (devlink_region_get_by_name(devlink, ops->name)) { 92418c2ecf20Sopenharmony_ci err = -EEXIST; 92428c2ecf20Sopenharmony_ci goto unlock; 92438c2ecf20Sopenharmony_ci } 92448c2ecf20Sopenharmony_ci 92458c2ecf20Sopenharmony_ci region = kzalloc(sizeof(*region), GFP_KERNEL); 92468c2ecf20Sopenharmony_ci if (!region) { 92478c2ecf20Sopenharmony_ci err = -ENOMEM; 92488c2ecf20Sopenharmony_ci goto unlock; 92498c2ecf20Sopenharmony_ci } 92508c2ecf20Sopenharmony_ci 92518c2ecf20Sopenharmony_ci region->devlink = devlink; 92528c2ecf20Sopenharmony_ci region->max_snapshots = region_max_snapshots; 92538c2ecf20Sopenharmony_ci region->ops = ops; 92548c2ecf20Sopenharmony_ci region->size = region_size; 92558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(®ion->snapshot_list); 92568c2ecf20Sopenharmony_ci list_add_tail(®ion->list, &devlink->region_list); 92578c2ecf20Sopenharmony_ci devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW); 92588c2ecf20Sopenharmony_ci 92598c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 92608c2ecf20Sopenharmony_ci return region; 92618c2ecf20Sopenharmony_ci 92628c2ecf20Sopenharmony_ciunlock: 92638c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 92648c2ecf20Sopenharmony_ci return ERR_PTR(err); 92658c2ecf20Sopenharmony_ci} 92668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_create); 92678c2ecf20Sopenharmony_ci 92688c2ecf20Sopenharmony_ci/** 92698c2ecf20Sopenharmony_ci * devlink_port_region_create - create a new address region for a port 92708c2ecf20Sopenharmony_ci * 92718c2ecf20Sopenharmony_ci * @port: devlink port 92728c2ecf20Sopenharmony_ci * @ops: region operations and name 92738c2ecf20Sopenharmony_ci * @region_max_snapshots: Maximum supported number of snapshots for region 92748c2ecf20Sopenharmony_ci * @region_size: size of region 92758c2ecf20Sopenharmony_ci */ 92768c2ecf20Sopenharmony_cistruct devlink_region * 92778c2ecf20Sopenharmony_cidevlink_port_region_create(struct devlink_port *port, 92788c2ecf20Sopenharmony_ci const struct devlink_port_region_ops *ops, 92798c2ecf20Sopenharmony_ci u32 region_max_snapshots, u64 region_size) 92808c2ecf20Sopenharmony_ci{ 92818c2ecf20Sopenharmony_ci struct devlink *devlink = port->devlink; 92828c2ecf20Sopenharmony_ci struct devlink_region *region; 92838c2ecf20Sopenharmony_ci int err = 0; 92848c2ecf20Sopenharmony_ci 92858c2ecf20Sopenharmony_ci if (WARN_ON(!ops) || WARN_ON(!ops->destructor)) 92868c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 92878c2ecf20Sopenharmony_ci 92888c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 92898c2ecf20Sopenharmony_ci 92908c2ecf20Sopenharmony_ci if (devlink_port_region_get_by_name(port, ops->name)) { 92918c2ecf20Sopenharmony_ci err = -EEXIST; 92928c2ecf20Sopenharmony_ci goto unlock; 92938c2ecf20Sopenharmony_ci } 92948c2ecf20Sopenharmony_ci 92958c2ecf20Sopenharmony_ci region = kzalloc(sizeof(*region), GFP_KERNEL); 92968c2ecf20Sopenharmony_ci if (!region) { 92978c2ecf20Sopenharmony_ci err = -ENOMEM; 92988c2ecf20Sopenharmony_ci goto unlock; 92998c2ecf20Sopenharmony_ci } 93008c2ecf20Sopenharmony_ci 93018c2ecf20Sopenharmony_ci region->devlink = devlink; 93028c2ecf20Sopenharmony_ci region->port = port; 93038c2ecf20Sopenharmony_ci region->max_snapshots = region_max_snapshots; 93048c2ecf20Sopenharmony_ci region->port_ops = ops; 93058c2ecf20Sopenharmony_ci region->size = region_size; 93068c2ecf20Sopenharmony_ci INIT_LIST_HEAD(®ion->snapshot_list); 93078c2ecf20Sopenharmony_ci list_add_tail(®ion->list, &port->region_list); 93088c2ecf20Sopenharmony_ci devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW); 93098c2ecf20Sopenharmony_ci 93108c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 93118c2ecf20Sopenharmony_ci return region; 93128c2ecf20Sopenharmony_ci 93138c2ecf20Sopenharmony_ciunlock: 93148c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 93158c2ecf20Sopenharmony_ci return ERR_PTR(err); 93168c2ecf20Sopenharmony_ci} 93178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_region_create); 93188c2ecf20Sopenharmony_ci 93198c2ecf20Sopenharmony_ci/** 93208c2ecf20Sopenharmony_ci * devlink_region_destroy - destroy address region 93218c2ecf20Sopenharmony_ci * 93228c2ecf20Sopenharmony_ci * @region: devlink region to destroy 93238c2ecf20Sopenharmony_ci */ 93248c2ecf20Sopenharmony_civoid devlink_region_destroy(struct devlink_region *region) 93258c2ecf20Sopenharmony_ci{ 93268c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 93278c2ecf20Sopenharmony_ci struct devlink_snapshot *snapshot, *ts; 93288c2ecf20Sopenharmony_ci 93298c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 93308c2ecf20Sopenharmony_ci 93318c2ecf20Sopenharmony_ci /* Free all snapshots of region */ 93328c2ecf20Sopenharmony_ci list_for_each_entry_safe(snapshot, ts, ®ion->snapshot_list, list) 93338c2ecf20Sopenharmony_ci devlink_region_snapshot_del(region, snapshot); 93348c2ecf20Sopenharmony_ci 93358c2ecf20Sopenharmony_ci list_del(®ion->list); 93368c2ecf20Sopenharmony_ci 93378c2ecf20Sopenharmony_ci devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL); 93388c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 93398c2ecf20Sopenharmony_ci kfree(region); 93408c2ecf20Sopenharmony_ci} 93418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_destroy); 93428c2ecf20Sopenharmony_ci 93438c2ecf20Sopenharmony_ci/** 93448c2ecf20Sopenharmony_ci * devlink_region_snapshot_id_get - get snapshot ID 93458c2ecf20Sopenharmony_ci * 93468c2ecf20Sopenharmony_ci * This callback should be called when adding a new snapshot, 93478c2ecf20Sopenharmony_ci * Driver should use the same id for multiple snapshots taken 93488c2ecf20Sopenharmony_ci * on multiple regions at the same time/by the same trigger. 93498c2ecf20Sopenharmony_ci * 93508c2ecf20Sopenharmony_ci * The caller of this function must use devlink_region_snapshot_id_put 93518c2ecf20Sopenharmony_ci * when finished creating regions using this id. 93528c2ecf20Sopenharmony_ci * 93538c2ecf20Sopenharmony_ci * Returns zero on success, or a negative error code on failure. 93548c2ecf20Sopenharmony_ci * 93558c2ecf20Sopenharmony_ci * @devlink: devlink 93568c2ecf20Sopenharmony_ci * @id: storage to return id 93578c2ecf20Sopenharmony_ci */ 93588c2ecf20Sopenharmony_ciint devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id) 93598c2ecf20Sopenharmony_ci{ 93608c2ecf20Sopenharmony_ci int err; 93618c2ecf20Sopenharmony_ci 93628c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 93638c2ecf20Sopenharmony_ci err = __devlink_region_snapshot_id_get(devlink, id); 93648c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 93658c2ecf20Sopenharmony_ci 93668c2ecf20Sopenharmony_ci return err; 93678c2ecf20Sopenharmony_ci} 93688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get); 93698c2ecf20Sopenharmony_ci 93708c2ecf20Sopenharmony_ci/** 93718c2ecf20Sopenharmony_ci * devlink_region_snapshot_id_put - put snapshot ID reference 93728c2ecf20Sopenharmony_ci * 93738c2ecf20Sopenharmony_ci * This should be called by a driver after finishing creating snapshots 93748c2ecf20Sopenharmony_ci * with an id. Doing so ensures that the ID can later be released in the 93758c2ecf20Sopenharmony_ci * event that all snapshots using it have been destroyed. 93768c2ecf20Sopenharmony_ci * 93778c2ecf20Sopenharmony_ci * @devlink: devlink 93788c2ecf20Sopenharmony_ci * @id: id to release reference on 93798c2ecf20Sopenharmony_ci */ 93808c2ecf20Sopenharmony_civoid devlink_region_snapshot_id_put(struct devlink *devlink, u32 id) 93818c2ecf20Sopenharmony_ci{ 93828c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 93838c2ecf20Sopenharmony_ci __devlink_snapshot_id_decrement(devlink, id); 93848c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 93858c2ecf20Sopenharmony_ci} 93868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put); 93878c2ecf20Sopenharmony_ci 93888c2ecf20Sopenharmony_ci/** 93898c2ecf20Sopenharmony_ci * devlink_region_snapshot_create - create a new snapshot 93908c2ecf20Sopenharmony_ci * This will add a new snapshot of a region. The snapshot 93918c2ecf20Sopenharmony_ci * will be stored on the region struct and can be accessed 93928c2ecf20Sopenharmony_ci * from devlink. This is useful for future analyses of snapshots. 93938c2ecf20Sopenharmony_ci * Multiple snapshots can be created on a region. 93948c2ecf20Sopenharmony_ci * The @snapshot_id should be obtained using the getter function. 93958c2ecf20Sopenharmony_ci * 93968c2ecf20Sopenharmony_ci * @region: devlink region of the snapshot 93978c2ecf20Sopenharmony_ci * @data: snapshot data 93988c2ecf20Sopenharmony_ci * @snapshot_id: snapshot id to be created 93998c2ecf20Sopenharmony_ci */ 94008c2ecf20Sopenharmony_ciint devlink_region_snapshot_create(struct devlink_region *region, 94018c2ecf20Sopenharmony_ci u8 *data, u32 snapshot_id) 94028c2ecf20Sopenharmony_ci{ 94038c2ecf20Sopenharmony_ci struct devlink *devlink = region->devlink; 94048c2ecf20Sopenharmony_ci int err; 94058c2ecf20Sopenharmony_ci 94068c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 94078c2ecf20Sopenharmony_ci err = __devlink_region_snapshot_create(region, data, snapshot_id); 94088c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 94098c2ecf20Sopenharmony_ci 94108c2ecf20Sopenharmony_ci return err; 94118c2ecf20Sopenharmony_ci} 94128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_create); 94138c2ecf20Sopenharmony_ci 94148c2ecf20Sopenharmony_ci#define DEVLINK_TRAP(_id, _type) \ 94158c2ecf20Sopenharmony_ci { \ 94168c2ecf20Sopenharmony_ci .type = DEVLINK_TRAP_TYPE_##_type, \ 94178c2ecf20Sopenharmony_ci .id = DEVLINK_TRAP_GENERIC_ID_##_id, \ 94188c2ecf20Sopenharmony_ci .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \ 94198c2ecf20Sopenharmony_ci } 94208c2ecf20Sopenharmony_ci 94218c2ecf20Sopenharmony_cistatic const struct devlink_trap devlink_trap_generic[] = { 94228c2ecf20Sopenharmony_ci DEVLINK_TRAP(SMAC_MC, DROP), 94238c2ecf20Sopenharmony_ci DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP), 94248c2ecf20Sopenharmony_ci DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP), 94258c2ecf20Sopenharmony_ci DEVLINK_TRAP(INGRESS_STP_FILTER, DROP), 94268c2ecf20Sopenharmony_ci DEVLINK_TRAP(EMPTY_TX_LIST, DROP), 94278c2ecf20Sopenharmony_ci DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP), 94288c2ecf20Sopenharmony_ci DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP), 94298c2ecf20Sopenharmony_ci DEVLINK_TRAP(TTL_ERROR, EXCEPTION), 94308c2ecf20Sopenharmony_ci DEVLINK_TRAP(TAIL_DROP, DROP), 94318c2ecf20Sopenharmony_ci DEVLINK_TRAP(NON_IP_PACKET, DROP), 94328c2ecf20Sopenharmony_ci DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP), 94338c2ecf20Sopenharmony_ci DEVLINK_TRAP(DIP_LB, DROP), 94348c2ecf20Sopenharmony_ci DEVLINK_TRAP(SIP_MC, DROP), 94358c2ecf20Sopenharmony_ci DEVLINK_TRAP(SIP_LB, DROP), 94368c2ecf20Sopenharmony_ci DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP), 94378c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_SIP_BC, DROP), 94388c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP), 94398c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP), 94408c2ecf20Sopenharmony_ci DEVLINK_TRAP(MTU_ERROR, EXCEPTION), 94418c2ecf20Sopenharmony_ci DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION), 94428c2ecf20Sopenharmony_ci DEVLINK_TRAP(RPF, EXCEPTION), 94438c2ecf20Sopenharmony_ci DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION), 94448c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION), 94458c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION), 94468c2ecf20Sopenharmony_ci DEVLINK_TRAP(NON_ROUTABLE, DROP), 94478c2ecf20Sopenharmony_ci DEVLINK_TRAP(DECAP_ERROR, EXCEPTION), 94488c2ecf20Sopenharmony_ci DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP), 94498c2ecf20Sopenharmony_ci DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP), 94508c2ecf20Sopenharmony_ci DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP), 94518c2ecf20Sopenharmony_ci DEVLINK_TRAP(STP, CONTROL), 94528c2ecf20Sopenharmony_ci DEVLINK_TRAP(LACP, CONTROL), 94538c2ecf20Sopenharmony_ci DEVLINK_TRAP(LLDP, CONTROL), 94548c2ecf20Sopenharmony_ci DEVLINK_TRAP(IGMP_QUERY, CONTROL), 94558c2ecf20Sopenharmony_ci DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL), 94568c2ecf20Sopenharmony_ci DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL), 94578c2ecf20Sopenharmony_ci DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL), 94588c2ecf20Sopenharmony_ci DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL), 94598c2ecf20Sopenharmony_ci DEVLINK_TRAP(MLD_QUERY, CONTROL), 94608c2ecf20Sopenharmony_ci DEVLINK_TRAP(MLD_V1_REPORT, CONTROL), 94618c2ecf20Sopenharmony_ci DEVLINK_TRAP(MLD_V2_REPORT, CONTROL), 94628c2ecf20Sopenharmony_ci DEVLINK_TRAP(MLD_V1_DONE, CONTROL), 94638c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_DHCP, CONTROL), 94648c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_DHCP, CONTROL), 94658c2ecf20Sopenharmony_ci DEVLINK_TRAP(ARP_REQUEST, CONTROL), 94668c2ecf20Sopenharmony_ci DEVLINK_TRAP(ARP_RESPONSE, CONTROL), 94678c2ecf20Sopenharmony_ci DEVLINK_TRAP(ARP_OVERLAY, CONTROL), 94688c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL), 94698c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL), 94708c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_BFD, CONTROL), 94718c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_BFD, CONTROL), 94728c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_OSPF, CONTROL), 94738c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_OSPF, CONTROL), 94748c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_BGP, CONTROL), 94758c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_BGP, CONTROL), 94768c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_VRRP, CONTROL), 94778c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_VRRP, CONTROL), 94788c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_PIM, CONTROL), 94798c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_PIM, CONTROL), 94808c2ecf20Sopenharmony_ci DEVLINK_TRAP(UC_LB, CONTROL), 94818c2ecf20Sopenharmony_ci DEVLINK_TRAP(LOCAL_ROUTE, CONTROL), 94828c2ecf20Sopenharmony_ci DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL), 94838c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL), 94848c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL), 94858c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL), 94868c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL), 94878c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL), 94888c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_REDIRECT, CONTROL), 94898c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL), 94908c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL), 94918c2ecf20Sopenharmony_ci DEVLINK_TRAP(PTP_EVENT, CONTROL), 94928c2ecf20Sopenharmony_ci DEVLINK_TRAP(PTP_GENERAL, CONTROL), 94938c2ecf20Sopenharmony_ci DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL), 94948c2ecf20Sopenharmony_ci DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL), 94958c2ecf20Sopenharmony_ci DEVLINK_TRAP(EARLY_DROP, DROP), 94968c2ecf20Sopenharmony_ci DEVLINK_TRAP(VXLAN_PARSING, DROP), 94978c2ecf20Sopenharmony_ci DEVLINK_TRAP(LLC_SNAP_PARSING, DROP), 94988c2ecf20Sopenharmony_ci DEVLINK_TRAP(VLAN_PARSING, DROP), 94998c2ecf20Sopenharmony_ci DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP), 95008c2ecf20Sopenharmony_ci DEVLINK_TRAP(MPLS_PARSING, DROP), 95018c2ecf20Sopenharmony_ci DEVLINK_TRAP(ARP_PARSING, DROP), 95028c2ecf20Sopenharmony_ci DEVLINK_TRAP(IP_1_PARSING, DROP), 95038c2ecf20Sopenharmony_ci DEVLINK_TRAP(IP_N_PARSING, DROP), 95048c2ecf20Sopenharmony_ci DEVLINK_TRAP(GRE_PARSING, DROP), 95058c2ecf20Sopenharmony_ci DEVLINK_TRAP(UDP_PARSING, DROP), 95068c2ecf20Sopenharmony_ci DEVLINK_TRAP(TCP_PARSING, DROP), 95078c2ecf20Sopenharmony_ci DEVLINK_TRAP(IPSEC_PARSING, DROP), 95088c2ecf20Sopenharmony_ci DEVLINK_TRAP(SCTP_PARSING, DROP), 95098c2ecf20Sopenharmony_ci DEVLINK_TRAP(DCCP_PARSING, DROP), 95108c2ecf20Sopenharmony_ci DEVLINK_TRAP(GTP_PARSING, DROP), 95118c2ecf20Sopenharmony_ci DEVLINK_TRAP(ESP_PARSING, DROP), 95128c2ecf20Sopenharmony_ci}; 95138c2ecf20Sopenharmony_ci 95148c2ecf20Sopenharmony_ci#define DEVLINK_TRAP_GROUP(_id) \ 95158c2ecf20Sopenharmony_ci { \ 95168c2ecf20Sopenharmony_ci .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \ 95178c2ecf20Sopenharmony_ci .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \ 95188c2ecf20Sopenharmony_ci } 95198c2ecf20Sopenharmony_ci 95208c2ecf20Sopenharmony_cistatic const struct devlink_trap_group devlink_trap_group_generic[] = { 95218c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(L2_DROPS), 95228c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(L3_DROPS), 95238c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(L3_EXCEPTIONS), 95248c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(BUFFER_DROPS), 95258c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(TUNNEL_DROPS), 95268c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_DROPS), 95278c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(STP), 95288c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(LACP), 95298c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(LLDP), 95308c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(MC_SNOOPING), 95318c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(DHCP), 95328c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY), 95338c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(BFD), 95348c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(OSPF), 95358c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(BGP), 95368c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(VRRP), 95378c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(PIM), 95388c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(UC_LB), 95398c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(LOCAL_DELIVERY), 95408c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY), 95418c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(IPV6), 95428c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(PTP_EVENT), 95438c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(PTP_GENERAL), 95448c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_SAMPLE), 95458c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_TRAP), 95468c2ecf20Sopenharmony_ci DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS), 95478c2ecf20Sopenharmony_ci}; 95488c2ecf20Sopenharmony_ci 95498c2ecf20Sopenharmony_cistatic int devlink_trap_generic_verify(const struct devlink_trap *trap) 95508c2ecf20Sopenharmony_ci{ 95518c2ecf20Sopenharmony_ci if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX) 95528c2ecf20Sopenharmony_ci return -EINVAL; 95538c2ecf20Sopenharmony_ci 95548c2ecf20Sopenharmony_ci if (strcmp(trap->name, devlink_trap_generic[trap->id].name)) 95558c2ecf20Sopenharmony_ci return -EINVAL; 95568c2ecf20Sopenharmony_ci 95578c2ecf20Sopenharmony_ci if (trap->type != devlink_trap_generic[trap->id].type) 95588c2ecf20Sopenharmony_ci return -EINVAL; 95598c2ecf20Sopenharmony_ci 95608c2ecf20Sopenharmony_ci return 0; 95618c2ecf20Sopenharmony_ci} 95628c2ecf20Sopenharmony_ci 95638c2ecf20Sopenharmony_cistatic int devlink_trap_driver_verify(const struct devlink_trap *trap) 95648c2ecf20Sopenharmony_ci{ 95658c2ecf20Sopenharmony_ci int i; 95668c2ecf20Sopenharmony_ci 95678c2ecf20Sopenharmony_ci if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX) 95688c2ecf20Sopenharmony_ci return -EINVAL; 95698c2ecf20Sopenharmony_ci 95708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) { 95718c2ecf20Sopenharmony_ci if (!strcmp(trap->name, devlink_trap_generic[i].name)) 95728c2ecf20Sopenharmony_ci return -EEXIST; 95738c2ecf20Sopenharmony_ci } 95748c2ecf20Sopenharmony_ci 95758c2ecf20Sopenharmony_ci return 0; 95768c2ecf20Sopenharmony_ci} 95778c2ecf20Sopenharmony_ci 95788c2ecf20Sopenharmony_cistatic int devlink_trap_verify(const struct devlink_trap *trap) 95798c2ecf20Sopenharmony_ci{ 95808c2ecf20Sopenharmony_ci if (!trap || !trap->name) 95818c2ecf20Sopenharmony_ci return -EINVAL; 95828c2ecf20Sopenharmony_ci 95838c2ecf20Sopenharmony_ci if (trap->generic) 95848c2ecf20Sopenharmony_ci return devlink_trap_generic_verify(trap); 95858c2ecf20Sopenharmony_ci else 95868c2ecf20Sopenharmony_ci return devlink_trap_driver_verify(trap); 95878c2ecf20Sopenharmony_ci} 95888c2ecf20Sopenharmony_ci 95898c2ecf20Sopenharmony_cistatic int 95908c2ecf20Sopenharmony_cidevlink_trap_group_generic_verify(const struct devlink_trap_group *group) 95918c2ecf20Sopenharmony_ci{ 95928c2ecf20Sopenharmony_ci if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX) 95938c2ecf20Sopenharmony_ci return -EINVAL; 95948c2ecf20Sopenharmony_ci 95958c2ecf20Sopenharmony_ci if (strcmp(group->name, devlink_trap_group_generic[group->id].name)) 95968c2ecf20Sopenharmony_ci return -EINVAL; 95978c2ecf20Sopenharmony_ci 95988c2ecf20Sopenharmony_ci return 0; 95998c2ecf20Sopenharmony_ci} 96008c2ecf20Sopenharmony_ci 96018c2ecf20Sopenharmony_cistatic int 96028c2ecf20Sopenharmony_cidevlink_trap_group_driver_verify(const struct devlink_trap_group *group) 96038c2ecf20Sopenharmony_ci{ 96048c2ecf20Sopenharmony_ci int i; 96058c2ecf20Sopenharmony_ci 96068c2ecf20Sopenharmony_ci if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX) 96078c2ecf20Sopenharmony_ci return -EINVAL; 96088c2ecf20Sopenharmony_ci 96098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) { 96108c2ecf20Sopenharmony_ci if (!strcmp(group->name, devlink_trap_group_generic[i].name)) 96118c2ecf20Sopenharmony_ci return -EEXIST; 96128c2ecf20Sopenharmony_ci } 96138c2ecf20Sopenharmony_ci 96148c2ecf20Sopenharmony_ci return 0; 96158c2ecf20Sopenharmony_ci} 96168c2ecf20Sopenharmony_ci 96178c2ecf20Sopenharmony_cistatic int devlink_trap_group_verify(const struct devlink_trap_group *group) 96188c2ecf20Sopenharmony_ci{ 96198c2ecf20Sopenharmony_ci if (group->generic) 96208c2ecf20Sopenharmony_ci return devlink_trap_group_generic_verify(group); 96218c2ecf20Sopenharmony_ci else 96228c2ecf20Sopenharmony_ci return devlink_trap_group_driver_verify(group); 96238c2ecf20Sopenharmony_ci} 96248c2ecf20Sopenharmony_ci 96258c2ecf20Sopenharmony_cistatic void 96268c2ecf20Sopenharmony_cidevlink_trap_group_notify(struct devlink *devlink, 96278c2ecf20Sopenharmony_ci const struct devlink_trap_group_item *group_item, 96288c2ecf20Sopenharmony_ci enum devlink_command cmd) 96298c2ecf20Sopenharmony_ci{ 96308c2ecf20Sopenharmony_ci struct sk_buff *msg; 96318c2ecf20Sopenharmony_ci int err; 96328c2ecf20Sopenharmony_ci 96338c2ecf20Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW && 96348c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_GROUP_DEL); 96358c2ecf20Sopenharmony_ci 96368c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 96378c2ecf20Sopenharmony_ci if (!msg) 96388c2ecf20Sopenharmony_ci return; 96398c2ecf20Sopenharmony_ci 96408c2ecf20Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0, 96418c2ecf20Sopenharmony_ci 0); 96428c2ecf20Sopenharmony_ci if (err) { 96438c2ecf20Sopenharmony_ci nlmsg_free(msg); 96448c2ecf20Sopenharmony_ci return; 96458c2ecf20Sopenharmony_ci } 96468c2ecf20Sopenharmony_ci 96478c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 96488c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 96498c2ecf20Sopenharmony_ci} 96508c2ecf20Sopenharmony_ci 96518c2ecf20Sopenharmony_cistatic int 96528c2ecf20Sopenharmony_cidevlink_trap_item_group_link(struct devlink *devlink, 96538c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item) 96548c2ecf20Sopenharmony_ci{ 96558c2ecf20Sopenharmony_ci u16 group_id = trap_item->trap->init_group_id; 96568c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 96578c2ecf20Sopenharmony_ci 96588c2ecf20Sopenharmony_ci group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id); 96598c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!group_item)) 96608c2ecf20Sopenharmony_ci return -EINVAL; 96618c2ecf20Sopenharmony_ci 96628c2ecf20Sopenharmony_ci trap_item->group_item = group_item; 96638c2ecf20Sopenharmony_ci 96648c2ecf20Sopenharmony_ci return 0; 96658c2ecf20Sopenharmony_ci} 96668c2ecf20Sopenharmony_ci 96678c2ecf20Sopenharmony_cistatic void devlink_trap_notify(struct devlink *devlink, 96688c2ecf20Sopenharmony_ci const struct devlink_trap_item *trap_item, 96698c2ecf20Sopenharmony_ci enum devlink_command cmd) 96708c2ecf20Sopenharmony_ci{ 96718c2ecf20Sopenharmony_ci struct sk_buff *msg; 96728c2ecf20Sopenharmony_ci int err; 96738c2ecf20Sopenharmony_ci 96748c2ecf20Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW && 96758c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_DEL); 96768c2ecf20Sopenharmony_ci 96778c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 96788c2ecf20Sopenharmony_ci if (!msg) 96798c2ecf20Sopenharmony_ci return; 96808c2ecf20Sopenharmony_ci 96818c2ecf20Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0); 96828c2ecf20Sopenharmony_ci if (err) { 96838c2ecf20Sopenharmony_ci nlmsg_free(msg); 96848c2ecf20Sopenharmony_ci return; 96858c2ecf20Sopenharmony_ci } 96868c2ecf20Sopenharmony_ci 96878c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 96888c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 96898c2ecf20Sopenharmony_ci} 96908c2ecf20Sopenharmony_ci 96918c2ecf20Sopenharmony_cistatic int 96928c2ecf20Sopenharmony_cidevlink_trap_register(struct devlink *devlink, 96938c2ecf20Sopenharmony_ci const struct devlink_trap *trap, void *priv) 96948c2ecf20Sopenharmony_ci{ 96958c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 96968c2ecf20Sopenharmony_ci int err; 96978c2ecf20Sopenharmony_ci 96988c2ecf20Sopenharmony_ci if (devlink_trap_item_lookup(devlink, trap->name)) 96998c2ecf20Sopenharmony_ci return -EEXIST; 97008c2ecf20Sopenharmony_ci 97018c2ecf20Sopenharmony_ci trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL); 97028c2ecf20Sopenharmony_ci if (!trap_item) 97038c2ecf20Sopenharmony_ci return -ENOMEM; 97048c2ecf20Sopenharmony_ci 97058c2ecf20Sopenharmony_ci trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats); 97068c2ecf20Sopenharmony_ci if (!trap_item->stats) { 97078c2ecf20Sopenharmony_ci err = -ENOMEM; 97088c2ecf20Sopenharmony_ci goto err_stats_alloc; 97098c2ecf20Sopenharmony_ci } 97108c2ecf20Sopenharmony_ci 97118c2ecf20Sopenharmony_ci trap_item->trap = trap; 97128c2ecf20Sopenharmony_ci trap_item->action = trap->init_action; 97138c2ecf20Sopenharmony_ci trap_item->priv = priv; 97148c2ecf20Sopenharmony_ci 97158c2ecf20Sopenharmony_ci err = devlink_trap_item_group_link(devlink, trap_item); 97168c2ecf20Sopenharmony_ci if (err) 97178c2ecf20Sopenharmony_ci goto err_group_link; 97188c2ecf20Sopenharmony_ci 97198c2ecf20Sopenharmony_ci err = devlink->ops->trap_init(devlink, trap, trap_item); 97208c2ecf20Sopenharmony_ci if (err) 97218c2ecf20Sopenharmony_ci goto err_trap_init; 97228c2ecf20Sopenharmony_ci 97238c2ecf20Sopenharmony_ci list_add_tail(&trap_item->list, &devlink->trap_list); 97248c2ecf20Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW); 97258c2ecf20Sopenharmony_ci 97268c2ecf20Sopenharmony_ci return 0; 97278c2ecf20Sopenharmony_ci 97288c2ecf20Sopenharmony_cierr_trap_init: 97298c2ecf20Sopenharmony_cierr_group_link: 97308c2ecf20Sopenharmony_ci free_percpu(trap_item->stats); 97318c2ecf20Sopenharmony_cierr_stats_alloc: 97328c2ecf20Sopenharmony_ci kfree(trap_item); 97338c2ecf20Sopenharmony_ci return err; 97348c2ecf20Sopenharmony_ci} 97358c2ecf20Sopenharmony_ci 97368c2ecf20Sopenharmony_cistatic void devlink_trap_unregister(struct devlink *devlink, 97378c2ecf20Sopenharmony_ci const struct devlink_trap *trap) 97388c2ecf20Sopenharmony_ci{ 97398c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 97408c2ecf20Sopenharmony_ci 97418c2ecf20Sopenharmony_ci trap_item = devlink_trap_item_lookup(devlink, trap->name); 97428c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!trap_item)) 97438c2ecf20Sopenharmony_ci return; 97448c2ecf20Sopenharmony_ci 97458c2ecf20Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL); 97468c2ecf20Sopenharmony_ci list_del(&trap_item->list); 97478c2ecf20Sopenharmony_ci if (devlink->ops->trap_fini) 97488c2ecf20Sopenharmony_ci devlink->ops->trap_fini(devlink, trap, trap_item); 97498c2ecf20Sopenharmony_ci free_percpu(trap_item->stats); 97508c2ecf20Sopenharmony_ci kfree(trap_item); 97518c2ecf20Sopenharmony_ci} 97528c2ecf20Sopenharmony_ci 97538c2ecf20Sopenharmony_cistatic void devlink_trap_disable(struct devlink *devlink, 97548c2ecf20Sopenharmony_ci const struct devlink_trap *trap) 97558c2ecf20Sopenharmony_ci{ 97568c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item; 97578c2ecf20Sopenharmony_ci 97588c2ecf20Sopenharmony_ci trap_item = devlink_trap_item_lookup(devlink, trap->name); 97598c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!trap_item)) 97608c2ecf20Sopenharmony_ci return; 97618c2ecf20Sopenharmony_ci 97628c2ecf20Sopenharmony_ci devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP, 97638c2ecf20Sopenharmony_ci NULL); 97648c2ecf20Sopenharmony_ci trap_item->action = DEVLINK_TRAP_ACTION_DROP; 97658c2ecf20Sopenharmony_ci} 97668c2ecf20Sopenharmony_ci 97678c2ecf20Sopenharmony_ci/** 97688c2ecf20Sopenharmony_ci * devlink_traps_register - Register packet traps with devlink. 97698c2ecf20Sopenharmony_ci * @devlink: devlink. 97708c2ecf20Sopenharmony_ci * @traps: Packet traps. 97718c2ecf20Sopenharmony_ci * @traps_count: Count of provided packet traps. 97728c2ecf20Sopenharmony_ci * @priv: Driver private information. 97738c2ecf20Sopenharmony_ci * 97748c2ecf20Sopenharmony_ci * Return: Non-zero value on failure. 97758c2ecf20Sopenharmony_ci */ 97768c2ecf20Sopenharmony_ciint devlink_traps_register(struct devlink *devlink, 97778c2ecf20Sopenharmony_ci const struct devlink_trap *traps, 97788c2ecf20Sopenharmony_ci size_t traps_count, void *priv) 97798c2ecf20Sopenharmony_ci{ 97808c2ecf20Sopenharmony_ci int i, err; 97818c2ecf20Sopenharmony_ci 97828c2ecf20Sopenharmony_ci if (!devlink->ops->trap_init || !devlink->ops->trap_action_set) 97838c2ecf20Sopenharmony_ci return -EINVAL; 97848c2ecf20Sopenharmony_ci 97858c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 97868c2ecf20Sopenharmony_ci for (i = 0; i < traps_count; i++) { 97878c2ecf20Sopenharmony_ci const struct devlink_trap *trap = &traps[i]; 97888c2ecf20Sopenharmony_ci 97898c2ecf20Sopenharmony_ci err = devlink_trap_verify(trap); 97908c2ecf20Sopenharmony_ci if (err) 97918c2ecf20Sopenharmony_ci goto err_trap_verify; 97928c2ecf20Sopenharmony_ci 97938c2ecf20Sopenharmony_ci err = devlink_trap_register(devlink, trap, priv); 97948c2ecf20Sopenharmony_ci if (err) 97958c2ecf20Sopenharmony_ci goto err_trap_register; 97968c2ecf20Sopenharmony_ci } 97978c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 97988c2ecf20Sopenharmony_ci 97998c2ecf20Sopenharmony_ci return 0; 98008c2ecf20Sopenharmony_ci 98018c2ecf20Sopenharmony_cierr_trap_register: 98028c2ecf20Sopenharmony_cierr_trap_verify: 98038c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 98048c2ecf20Sopenharmony_ci devlink_trap_unregister(devlink, &traps[i]); 98058c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 98068c2ecf20Sopenharmony_ci return err; 98078c2ecf20Sopenharmony_ci} 98088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_register); 98098c2ecf20Sopenharmony_ci 98108c2ecf20Sopenharmony_ci/** 98118c2ecf20Sopenharmony_ci * devlink_traps_unregister - Unregister packet traps from devlink. 98128c2ecf20Sopenharmony_ci * @devlink: devlink. 98138c2ecf20Sopenharmony_ci * @traps: Packet traps. 98148c2ecf20Sopenharmony_ci * @traps_count: Count of provided packet traps. 98158c2ecf20Sopenharmony_ci */ 98168c2ecf20Sopenharmony_civoid devlink_traps_unregister(struct devlink *devlink, 98178c2ecf20Sopenharmony_ci const struct devlink_trap *traps, 98188c2ecf20Sopenharmony_ci size_t traps_count) 98198c2ecf20Sopenharmony_ci{ 98208c2ecf20Sopenharmony_ci int i; 98218c2ecf20Sopenharmony_ci 98228c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 98238c2ecf20Sopenharmony_ci /* Make sure we do not have any packets in-flight while unregistering 98248c2ecf20Sopenharmony_ci * traps by disabling all of them and waiting for a grace period. 98258c2ecf20Sopenharmony_ci */ 98268c2ecf20Sopenharmony_ci for (i = traps_count - 1; i >= 0; i--) 98278c2ecf20Sopenharmony_ci devlink_trap_disable(devlink, &traps[i]); 98288c2ecf20Sopenharmony_ci synchronize_rcu(); 98298c2ecf20Sopenharmony_ci for (i = traps_count - 1; i >= 0; i--) 98308c2ecf20Sopenharmony_ci devlink_trap_unregister(devlink, &traps[i]); 98318c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 98328c2ecf20Sopenharmony_ci} 98338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_unregister); 98348c2ecf20Sopenharmony_ci 98358c2ecf20Sopenharmony_cistatic void 98368c2ecf20Sopenharmony_cidevlink_trap_stats_update(struct devlink_stats __percpu *trap_stats, 98378c2ecf20Sopenharmony_ci size_t skb_len) 98388c2ecf20Sopenharmony_ci{ 98398c2ecf20Sopenharmony_ci struct devlink_stats *stats; 98408c2ecf20Sopenharmony_ci 98418c2ecf20Sopenharmony_ci stats = this_cpu_ptr(trap_stats); 98428c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 98438c2ecf20Sopenharmony_ci stats->rx_bytes += skb_len; 98448c2ecf20Sopenharmony_ci stats->rx_packets++; 98458c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 98468c2ecf20Sopenharmony_ci} 98478c2ecf20Sopenharmony_ci 98488c2ecf20Sopenharmony_cistatic void 98498c2ecf20Sopenharmony_cidevlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata, 98508c2ecf20Sopenharmony_ci const struct devlink_trap_item *trap_item, 98518c2ecf20Sopenharmony_ci struct devlink_port *in_devlink_port, 98528c2ecf20Sopenharmony_ci const struct flow_action_cookie *fa_cookie) 98538c2ecf20Sopenharmony_ci{ 98548c2ecf20Sopenharmony_ci metadata->trap_name = trap_item->trap->name; 98558c2ecf20Sopenharmony_ci metadata->trap_group_name = trap_item->group_item->group->name; 98568c2ecf20Sopenharmony_ci metadata->fa_cookie = fa_cookie; 98578c2ecf20Sopenharmony_ci metadata->trap_type = trap_item->trap->type; 98588c2ecf20Sopenharmony_ci 98598c2ecf20Sopenharmony_ci spin_lock(&in_devlink_port->type_lock); 98608c2ecf20Sopenharmony_ci if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH) 98618c2ecf20Sopenharmony_ci metadata->input_dev = in_devlink_port->type_dev; 98628c2ecf20Sopenharmony_ci spin_unlock(&in_devlink_port->type_lock); 98638c2ecf20Sopenharmony_ci} 98648c2ecf20Sopenharmony_ci 98658c2ecf20Sopenharmony_ci/** 98668c2ecf20Sopenharmony_ci * devlink_trap_report - Report trapped packet to drop monitor. 98678c2ecf20Sopenharmony_ci * @devlink: devlink. 98688c2ecf20Sopenharmony_ci * @skb: Trapped packet. 98698c2ecf20Sopenharmony_ci * @trap_ctx: Trap context. 98708c2ecf20Sopenharmony_ci * @in_devlink_port: Input devlink port. 98718c2ecf20Sopenharmony_ci * @fa_cookie: Flow action cookie. Could be NULL. 98728c2ecf20Sopenharmony_ci */ 98738c2ecf20Sopenharmony_civoid devlink_trap_report(struct devlink *devlink, struct sk_buff *skb, 98748c2ecf20Sopenharmony_ci void *trap_ctx, struct devlink_port *in_devlink_port, 98758c2ecf20Sopenharmony_ci const struct flow_action_cookie *fa_cookie) 98768c2ecf20Sopenharmony_ci 98778c2ecf20Sopenharmony_ci{ 98788c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item = trap_ctx; 98798c2ecf20Sopenharmony_ci 98808c2ecf20Sopenharmony_ci devlink_trap_stats_update(trap_item->stats, skb->len); 98818c2ecf20Sopenharmony_ci devlink_trap_stats_update(trap_item->group_item->stats, skb->len); 98828c2ecf20Sopenharmony_ci 98838c2ecf20Sopenharmony_ci if (trace_devlink_trap_report_enabled()) { 98848c2ecf20Sopenharmony_ci struct devlink_trap_metadata metadata = {}; 98858c2ecf20Sopenharmony_ci 98868c2ecf20Sopenharmony_ci devlink_trap_report_metadata_set(&metadata, trap_item, 98878c2ecf20Sopenharmony_ci in_devlink_port, fa_cookie); 98888c2ecf20Sopenharmony_ci trace_devlink_trap_report(devlink, skb, &metadata); 98898c2ecf20Sopenharmony_ci } 98908c2ecf20Sopenharmony_ci} 98918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_report); 98928c2ecf20Sopenharmony_ci 98938c2ecf20Sopenharmony_ci/** 98948c2ecf20Sopenharmony_ci * devlink_trap_ctx_priv - Trap context to driver private information. 98958c2ecf20Sopenharmony_ci * @trap_ctx: Trap context. 98968c2ecf20Sopenharmony_ci * 98978c2ecf20Sopenharmony_ci * Return: Driver private information passed during registration. 98988c2ecf20Sopenharmony_ci */ 98998c2ecf20Sopenharmony_civoid *devlink_trap_ctx_priv(void *trap_ctx) 99008c2ecf20Sopenharmony_ci{ 99018c2ecf20Sopenharmony_ci struct devlink_trap_item *trap_item = trap_ctx; 99028c2ecf20Sopenharmony_ci 99038c2ecf20Sopenharmony_ci return trap_item->priv; 99048c2ecf20Sopenharmony_ci} 99058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_ctx_priv); 99068c2ecf20Sopenharmony_ci 99078c2ecf20Sopenharmony_cistatic int 99088c2ecf20Sopenharmony_cidevlink_trap_group_item_policer_link(struct devlink *devlink, 99098c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item) 99108c2ecf20Sopenharmony_ci{ 99118c2ecf20Sopenharmony_ci u32 policer_id = group_item->group->init_policer_id; 99128c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 99138c2ecf20Sopenharmony_ci 99148c2ecf20Sopenharmony_ci if (policer_id == 0) 99158c2ecf20Sopenharmony_ci return 0; 99168c2ecf20Sopenharmony_ci 99178c2ecf20Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, policer_id); 99188c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!policer_item)) 99198c2ecf20Sopenharmony_ci return -EINVAL; 99208c2ecf20Sopenharmony_ci 99218c2ecf20Sopenharmony_ci group_item->policer_item = policer_item; 99228c2ecf20Sopenharmony_ci 99238c2ecf20Sopenharmony_ci return 0; 99248c2ecf20Sopenharmony_ci} 99258c2ecf20Sopenharmony_ci 99268c2ecf20Sopenharmony_cistatic int 99278c2ecf20Sopenharmony_cidevlink_trap_group_register(struct devlink *devlink, 99288c2ecf20Sopenharmony_ci const struct devlink_trap_group *group) 99298c2ecf20Sopenharmony_ci{ 99308c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 99318c2ecf20Sopenharmony_ci int err; 99328c2ecf20Sopenharmony_ci 99338c2ecf20Sopenharmony_ci if (devlink_trap_group_item_lookup(devlink, group->name)) 99348c2ecf20Sopenharmony_ci return -EEXIST; 99358c2ecf20Sopenharmony_ci 99368c2ecf20Sopenharmony_ci group_item = kzalloc(sizeof(*group_item), GFP_KERNEL); 99378c2ecf20Sopenharmony_ci if (!group_item) 99388c2ecf20Sopenharmony_ci return -ENOMEM; 99398c2ecf20Sopenharmony_ci 99408c2ecf20Sopenharmony_ci group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats); 99418c2ecf20Sopenharmony_ci if (!group_item->stats) { 99428c2ecf20Sopenharmony_ci err = -ENOMEM; 99438c2ecf20Sopenharmony_ci goto err_stats_alloc; 99448c2ecf20Sopenharmony_ci } 99458c2ecf20Sopenharmony_ci 99468c2ecf20Sopenharmony_ci group_item->group = group; 99478c2ecf20Sopenharmony_ci 99488c2ecf20Sopenharmony_ci err = devlink_trap_group_item_policer_link(devlink, group_item); 99498c2ecf20Sopenharmony_ci if (err) 99508c2ecf20Sopenharmony_ci goto err_policer_link; 99518c2ecf20Sopenharmony_ci 99528c2ecf20Sopenharmony_ci if (devlink->ops->trap_group_init) { 99538c2ecf20Sopenharmony_ci err = devlink->ops->trap_group_init(devlink, group); 99548c2ecf20Sopenharmony_ci if (err) 99558c2ecf20Sopenharmony_ci goto err_group_init; 99568c2ecf20Sopenharmony_ci } 99578c2ecf20Sopenharmony_ci 99588c2ecf20Sopenharmony_ci list_add_tail(&group_item->list, &devlink->trap_group_list); 99598c2ecf20Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 99608c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW); 99618c2ecf20Sopenharmony_ci 99628c2ecf20Sopenharmony_ci return 0; 99638c2ecf20Sopenharmony_ci 99648c2ecf20Sopenharmony_cierr_group_init: 99658c2ecf20Sopenharmony_cierr_policer_link: 99668c2ecf20Sopenharmony_ci free_percpu(group_item->stats); 99678c2ecf20Sopenharmony_cierr_stats_alloc: 99688c2ecf20Sopenharmony_ci kfree(group_item); 99698c2ecf20Sopenharmony_ci return err; 99708c2ecf20Sopenharmony_ci} 99718c2ecf20Sopenharmony_ci 99728c2ecf20Sopenharmony_cistatic void 99738c2ecf20Sopenharmony_cidevlink_trap_group_unregister(struct devlink *devlink, 99748c2ecf20Sopenharmony_ci const struct devlink_trap_group *group) 99758c2ecf20Sopenharmony_ci{ 99768c2ecf20Sopenharmony_ci struct devlink_trap_group_item *group_item; 99778c2ecf20Sopenharmony_ci 99788c2ecf20Sopenharmony_ci group_item = devlink_trap_group_item_lookup(devlink, group->name); 99798c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!group_item)) 99808c2ecf20Sopenharmony_ci return; 99818c2ecf20Sopenharmony_ci 99828c2ecf20Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 99838c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_DEL); 99848c2ecf20Sopenharmony_ci list_del(&group_item->list); 99858c2ecf20Sopenharmony_ci free_percpu(group_item->stats); 99868c2ecf20Sopenharmony_ci kfree(group_item); 99878c2ecf20Sopenharmony_ci} 99888c2ecf20Sopenharmony_ci 99898c2ecf20Sopenharmony_ci/** 99908c2ecf20Sopenharmony_ci * devlink_trap_groups_register - Register packet trap groups with devlink. 99918c2ecf20Sopenharmony_ci * @devlink: devlink. 99928c2ecf20Sopenharmony_ci * @groups: Packet trap groups. 99938c2ecf20Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 99948c2ecf20Sopenharmony_ci * 99958c2ecf20Sopenharmony_ci * Return: Non-zero value on failure. 99968c2ecf20Sopenharmony_ci */ 99978c2ecf20Sopenharmony_ciint devlink_trap_groups_register(struct devlink *devlink, 99988c2ecf20Sopenharmony_ci const struct devlink_trap_group *groups, 99998c2ecf20Sopenharmony_ci size_t groups_count) 100008c2ecf20Sopenharmony_ci{ 100018c2ecf20Sopenharmony_ci int i, err; 100028c2ecf20Sopenharmony_ci 100038c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 100048c2ecf20Sopenharmony_ci for (i = 0; i < groups_count; i++) { 100058c2ecf20Sopenharmony_ci const struct devlink_trap_group *group = &groups[i]; 100068c2ecf20Sopenharmony_ci 100078c2ecf20Sopenharmony_ci err = devlink_trap_group_verify(group); 100088c2ecf20Sopenharmony_ci if (err) 100098c2ecf20Sopenharmony_ci goto err_trap_group_verify; 100108c2ecf20Sopenharmony_ci 100118c2ecf20Sopenharmony_ci err = devlink_trap_group_register(devlink, group); 100128c2ecf20Sopenharmony_ci if (err) 100138c2ecf20Sopenharmony_ci goto err_trap_group_register; 100148c2ecf20Sopenharmony_ci } 100158c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 100168c2ecf20Sopenharmony_ci 100178c2ecf20Sopenharmony_ci return 0; 100188c2ecf20Sopenharmony_ci 100198c2ecf20Sopenharmony_cierr_trap_group_register: 100208c2ecf20Sopenharmony_cierr_trap_group_verify: 100218c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 100228c2ecf20Sopenharmony_ci devlink_trap_group_unregister(devlink, &groups[i]); 100238c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 100248c2ecf20Sopenharmony_ci return err; 100258c2ecf20Sopenharmony_ci} 100268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_register); 100278c2ecf20Sopenharmony_ci 100288c2ecf20Sopenharmony_ci/** 100298c2ecf20Sopenharmony_ci * devlink_trap_groups_unregister - Unregister packet trap groups from devlink. 100308c2ecf20Sopenharmony_ci * @devlink: devlink. 100318c2ecf20Sopenharmony_ci * @groups: Packet trap groups. 100328c2ecf20Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 100338c2ecf20Sopenharmony_ci */ 100348c2ecf20Sopenharmony_civoid devlink_trap_groups_unregister(struct devlink *devlink, 100358c2ecf20Sopenharmony_ci const struct devlink_trap_group *groups, 100368c2ecf20Sopenharmony_ci size_t groups_count) 100378c2ecf20Sopenharmony_ci{ 100388c2ecf20Sopenharmony_ci int i; 100398c2ecf20Sopenharmony_ci 100408c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 100418c2ecf20Sopenharmony_ci for (i = groups_count - 1; i >= 0; i--) 100428c2ecf20Sopenharmony_ci devlink_trap_group_unregister(devlink, &groups[i]); 100438c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 100448c2ecf20Sopenharmony_ci} 100458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_unregister); 100468c2ecf20Sopenharmony_ci 100478c2ecf20Sopenharmony_cistatic void 100488c2ecf20Sopenharmony_cidevlink_trap_policer_notify(struct devlink *devlink, 100498c2ecf20Sopenharmony_ci const struct devlink_trap_policer_item *policer_item, 100508c2ecf20Sopenharmony_ci enum devlink_command cmd) 100518c2ecf20Sopenharmony_ci{ 100528c2ecf20Sopenharmony_ci struct sk_buff *msg; 100538c2ecf20Sopenharmony_ci int err; 100548c2ecf20Sopenharmony_ci 100558c2ecf20Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW && 100568c2ecf20Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_POLICER_DEL); 100578c2ecf20Sopenharmony_ci 100588c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 100598c2ecf20Sopenharmony_ci if (!msg) 100608c2ecf20Sopenharmony_ci return; 100618c2ecf20Sopenharmony_ci 100628c2ecf20Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0, 100638c2ecf20Sopenharmony_ci 0, 0); 100648c2ecf20Sopenharmony_ci if (err) { 100658c2ecf20Sopenharmony_ci nlmsg_free(msg); 100668c2ecf20Sopenharmony_ci return; 100678c2ecf20Sopenharmony_ci } 100688c2ecf20Sopenharmony_ci 100698c2ecf20Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 100708c2ecf20Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 100718c2ecf20Sopenharmony_ci} 100728c2ecf20Sopenharmony_ci 100738c2ecf20Sopenharmony_cistatic int 100748c2ecf20Sopenharmony_cidevlink_trap_policer_register(struct devlink *devlink, 100758c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer) 100768c2ecf20Sopenharmony_ci{ 100778c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 100788c2ecf20Sopenharmony_ci int err; 100798c2ecf20Sopenharmony_ci 100808c2ecf20Sopenharmony_ci if (devlink_trap_policer_item_lookup(devlink, policer->id)) 100818c2ecf20Sopenharmony_ci return -EEXIST; 100828c2ecf20Sopenharmony_ci 100838c2ecf20Sopenharmony_ci policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL); 100848c2ecf20Sopenharmony_ci if (!policer_item) 100858c2ecf20Sopenharmony_ci return -ENOMEM; 100868c2ecf20Sopenharmony_ci 100878c2ecf20Sopenharmony_ci policer_item->policer = policer; 100888c2ecf20Sopenharmony_ci policer_item->rate = policer->init_rate; 100898c2ecf20Sopenharmony_ci policer_item->burst = policer->init_burst; 100908c2ecf20Sopenharmony_ci 100918c2ecf20Sopenharmony_ci if (devlink->ops->trap_policer_init) { 100928c2ecf20Sopenharmony_ci err = devlink->ops->trap_policer_init(devlink, policer); 100938c2ecf20Sopenharmony_ci if (err) 100948c2ecf20Sopenharmony_ci goto err_policer_init; 100958c2ecf20Sopenharmony_ci } 100968c2ecf20Sopenharmony_ci 100978c2ecf20Sopenharmony_ci list_add_tail(&policer_item->list, &devlink->trap_policer_list); 100988c2ecf20Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 100998c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW); 101008c2ecf20Sopenharmony_ci 101018c2ecf20Sopenharmony_ci return 0; 101028c2ecf20Sopenharmony_ci 101038c2ecf20Sopenharmony_cierr_policer_init: 101048c2ecf20Sopenharmony_ci kfree(policer_item); 101058c2ecf20Sopenharmony_ci return err; 101068c2ecf20Sopenharmony_ci} 101078c2ecf20Sopenharmony_ci 101088c2ecf20Sopenharmony_cistatic void 101098c2ecf20Sopenharmony_cidevlink_trap_policer_unregister(struct devlink *devlink, 101108c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer) 101118c2ecf20Sopenharmony_ci{ 101128c2ecf20Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 101138c2ecf20Sopenharmony_ci 101148c2ecf20Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, policer->id); 101158c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!policer_item)) 101168c2ecf20Sopenharmony_ci return; 101178c2ecf20Sopenharmony_ci 101188c2ecf20Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 101198c2ecf20Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_DEL); 101208c2ecf20Sopenharmony_ci list_del(&policer_item->list); 101218c2ecf20Sopenharmony_ci if (devlink->ops->trap_policer_fini) 101228c2ecf20Sopenharmony_ci devlink->ops->trap_policer_fini(devlink, policer); 101238c2ecf20Sopenharmony_ci kfree(policer_item); 101248c2ecf20Sopenharmony_ci} 101258c2ecf20Sopenharmony_ci 101268c2ecf20Sopenharmony_ci/** 101278c2ecf20Sopenharmony_ci * devlink_trap_policers_register - Register packet trap policers with devlink. 101288c2ecf20Sopenharmony_ci * @devlink: devlink. 101298c2ecf20Sopenharmony_ci * @policers: Packet trap policers. 101308c2ecf20Sopenharmony_ci * @policers_count: Count of provided packet trap policers. 101318c2ecf20Sopenharmony_ci * 101328c2ecf20Sopenharmony_ci * Return: Non-zero value on failure. 101338c2ecf20Sopenharmony_ci */ 101348c2ecf20Sopenharmony_ciint 101358c2ecf20Sopenharmony_cidevlink_trap_policers_register(struct devlink *devlink, 101368c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policers, 101378c2ecf20Sopenharmony_ci size_t policers_count) 101388c2ecf20Sopenharmony_ci{ 101398c2ecf20Sopenharmony_ci int i, err; 101408c2ecf20Sopenharmony_ci 101418c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 101428c2ecf20Sopenharmony_ci for (i = 0; i < policers_count; i++) { 101438c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policer = &policers[i]; 101448c2ecf20Sopenharmony_ci 101458c2ecf20Sopenharmony_ci if (WARN_ON(policer->id == 0 || 101468c2ecf20Sopenharmony_ci policer->max_rate < policer->min_rate || 101478c2ecf20Sopenharmony_ci policer->max_burst < policer->min_burst)) { 101488c2ecf20Sopenharmony_ci err = -EINVAL; 101498c2ecf20Sopenharmony_ci goto err_trap_policer_verify; 101508c2ecf20Sopenharmony_ci } 101518c2ecf20Sopenharmony_ci 101528c2ecf20Sopenharmony_ci err = devlink_trap_policer_register(devlink, policer); 101538c2ecf20Sopenharmony_ci if (err) 101548c2ecf20Sopenharmony_ci goto err_trap_policer_register; 101558c2ecf20Sopenharmony_ci } 101568c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 101578c2ecf20Sopenharmony_ci 101588c2ecf20Sopenharmony_ci return 0; 101598c2ecf20Sopenharmony_ci 101608c2ecf20Sopenharmony_cierr_trap_policer_register: 101618c2ecf20Sopenharmony_cierr_trap_policer_verify: 101628c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 101638c2ecf20Sopenharmony_ci devlink_trap_policer_unregister(devlink, &policers[i]); 101648c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 101658c2ecf20Sopenharmony_ci return err; 101668c2ecf20Sopenharmony_ci} 101678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_policers_register); 101688c2ecf20Sopenharmony_ci 101698c2ecf20Sopenharmony_ci/** 101708c2ecf20Sopenharmony_ci * devlink_trap_policers_unregister - Unregister packet trap policers from devlink. 101718c2ecf20Sopenharmony_ci * @devlink: devlink. 101728c2ecf20Sopenharmony_ci * @policers: Packet trap policers. 101738c2ecf20Sopenharmony_ci * @policers_count: Count of provided packet trap policers. 101748c2ecf20Sopenharmony_ci */ 101758c2ecf20Sopenharmony_civoid 101768c2ecf20Sopenharmony_cidevlink_trap_policers_unregister(struct devlink *devlink, 101778c2ecf20Sopenharmony_ci const struct devlink_trap_policer *policers, 101788c2ecf20Sopenharmony_ci size_t policers_count) 101798c2ecf20Sopenharmony_ci{ 101808c2ecf20Sopenharmony_ci int i; 101818c2ecf20Sopenharmony_ci 101828c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 101838c2ecf20Sopenharmony_ci for (i = policers_count - 1; i >= 0; i--) 101848c2ecf20Sopenharmony_ci devlink_trap_policer_unregister(devlink, &policers[i]); 101858c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 101868c2ecf20Sopenharmony_ci} 101878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_policers_unregister); 101888c2ecf20Sopenharmony_ci 101898c2ecf20Sopenharmony_cistatic void __devlink_compat_running_version(struct devlink *devlink, 101908c2ecf20Sopenharmony_ci char *buf, size_t len) 101918c2ecf20Sopenharmony_ci{ 101928c2ecf20Sopenharmony_ci const struct nlattr *nlattr; 101938c2ecf20Sopenharmony_ci struct devlink_info_req req; 101948c2ecf20Sopenharmony_ci struct sk_buff *msg; 101958c2ecf20Sopenharmony_ci int rem, err; 101968c2ecf20Sopenharmony_ci 101978c2ecf20Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 101988c2ecf20Sopenharmony_ci if (!msg) 101998c2ecf20Sopenharmony_ci return; 102008c2ecf20Sopenharmony_ci 102018c2ecf20Sopenharmony_ci req.msg = msg; 102028c2ecf20Sopenharmony_ci err = devlink->ops->info_get(devlink, &req, NULL); 102038c2ecf20Sopenharmony_ci if (err) 102048c2ecf20Sopenharmony_ci goto free_msg; 102058c2ecf20Sopenharmony_ci 102068c2ecf20Sopenharmony_ci nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) { 102078c2ecf20Sopenharmony_ci const struct nlattr *kv; 102088c2ecf20Sopenharmony_ci int rem_kv; 102098c2ecf20Sopenharmony_ci 102108c2ecf20Sopenharmony_ci if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING) 102118c2ecf20Sopenharmony_ci continue; 102128c2ecf20Sopenharmony_ci 102138c2ecf20Sopenharmony_ci nla_for_each_nested(kv, nlattr, rem_kv) { 102148c2ecf20Sopenharmony_ci if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE) 102158c2ecf20Sopenharmony_ci continue; 102168c2ecf20Sopenharmony_ci 102178c2ecf20Sopenharmony_ci strlcat(buf, nla_data(kv), len); 102188c2ecf20Sopenharmony_ci strlcat(buf, " ", len); 102198c2ecf20Sopenharmony_ci } 102208c2ecf20Sopenharmony_ci } 102218c2ecf20Sopenharmony_cifree_msg: 102228c2ecf20Sopenharmony_ci nlmsg_free(msg); 102238c2ecf20Sopenharmony_ci} 102248c2ecf20Sopenharmony_ci 102258c2ecf20Sopenharmony_civoid devlink_compat_running_version(struct net_device *dev, 102268c2ecf20Sopenharmony_ci char *buf, size_t len) 102278c2ecf20Sopenharmony_ci{ 102288c2ecf20Sopenharmony_ci struct devlink *devlink; 102298c2ecf20Sopenharmony_ci 102308c2ecf20Sopenharmony_ci dev_hold(dev); 102318c2ecf20Sopenharmony_ci rtnl_unlock(); 102328c2ecf20Sopenharmony_ci 102338c2ecf20Sopenharmony_ci devlink = netdev_to_devlink(dev); 102348c2ecf20Sopenharmony_ci if (!devlink || !devlink->ops->info_get) 102358c2ecf20Sopenharmony_ci goto out; 102368c2ecf20Sopenharmony_ci 102378c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 102388c2ecf20Sopenharmony_ci __devlink_compat_running_version(devlink, buf, len); 102398c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 102408c2ecf20Sopenharmony_ci 102418c2ecf20Sopenharmony_ciout: 102428c2ecf20Sopenharmony_ci rtnl_lock(); 102438c2ecf20Sopenharmony_ci dev_put(dev); 102448c2ecf20Sopenharmony_ci} 102458c2ecf20Sopenharmony_ci 102468c2ecf20Sopenharmony_ciint devlink_compat_flash_update(struct net_device *dev, const char *file_name) 102478c2ecf20Sopenharmony_ci{ 102488c2ecf20Sopenharmony_ci struct devlink_flash_update_params params = {}; 102498c2ecf20Sopenharmony_ci struct devlink *devlink; 102508c2ecf20Sopenharmony_ci int ret; 102518c2ecf20Sopenharmony_ci 102528c2ecf20Sopenharmony_ci dev_hold(dev); 102538c2ecf20Sopenharmony_ci rtnl_unlock(); 102548c2ecf20Sopenharmony_ci 102558c2ecf20Sopenharmony_ci devlink = netdev_to_devlink(dev); 102568c2ecf20Sopenharmony_ci if (!devlink || !devlink->ops->flash_update) { 102578c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 102588c2ecf20Sopenharmony_ci goto out; 102598c2ecf20Sopenharmony_ci } 102608c2ecf20Sopenharmony_ci 102618c2ecf20Sopenharmony_ci params.file_name = file_name; 102628c2ecf20Sopenharmony_ci 102638c2ecf20Sopenharmony_ci mutex_lock(&devlink->lock); 102648c2ecf20Sopenharmony_ci ret = devlink->ops->flash_update(devlink, ¶ms, NULL); 102658c2ecf20Sopenharmony_ci mutex_unlock(&devlink->lock); 102668c2ecf20Sopenharmony_ci 102678c2ecf20Sopenharmony_ciout: 102688c2ecf20Sopenharmony_ci rtnl_lock(); 102698c2ecf20Sopenharmony_ci dev_put(dev); 102708c2ecf20Sopenharmony_ci 102718c2ecf20Sopenharmony_ci return ret; 102728c2ecf20Sopenharmony_ci} 102738c2ecf20Sopenharmony_ci 102748c2ecf20Sopenharmony_ciint devlink_compat_phys_port_name_get(struct net_device *dev, 102758c2ecf20Sopenharmony_ci char *name, size_t len) 102768c2ecf20Sopenharmony_ci{ 102778c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 102788c2ecf20Sopenharmony_ci 102798c2ecf20Sopenharmony_ci /* RTNL mutex is held here which ensures that devlink_port 102808c2ecf20Sopenharmony_ci * instance cannot disappear in the middle. No need to take 102818c2ecf20Sopenharmony_ci * any devlink lock as only permanent values are accessed. 102828c2ecf20Sopenharmony_ci */ 102838c2ecf20Sopenharmony_ci ASSERT_RTNL(); 102848c2ecf20Sopenharmony_ci 102858c2ecf20Sopenharmony_ci devlink_port = netdev_to_devlink_port(dev); 102868c2ecf20Sopenharmony_ci if (!devlink_port) 102878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 102888c2ecf20Sopenharmony_ci 102898c2ecf20Sopenharmony_ci return __devlink_port_phys_port_name_get(devlink_port, name, len); 102908c2ecf20Sopenharmony_ci} 102918c2ecf20Sopenharmony_ci 102928c2ecf20Sopenharmony_ciint devlink_compat_switch_id_get(struct net_device *dev, 102938c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 102948c2ecf20Sopenharmony_ci{ 102958c2ecf20Sopenharmony_ci struct devlink_port *devlink_port; 102968c2ecf20Sopenharmony_ci 102978c2ecf20Sopenharmony_ci /* Caller must hold RTNL mutex or reference to dev, which ensures that 102988c2ecf20Sopenharmony_ci * devlink_port instance cannot disappear in the middle. No need to take 102998c2ecf20Sopenharmony_ci * any devlink lock as only permanent values are accessed. 103008c2ecf20Sopenharmony_ci */ 103018c2ecf20Sopenharmony_ci devlink_port = netdev_to_devlink_port(dev); 103028c2ecf20Sopenharmony_ci if (!devlink_port || !devlink_port->switch_port) 103038c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 103048c2ecf20Sopenharmony_ci 103058c2ecf20Sopenharmony_ci memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid)); 103068c2ecf20Sopenharmony_ci 103078c2ecf20Sopenharmony_ci return 0; 103088c2ecf20Sopenharmony_ci} 103098c2ecf20Sopenharmony_ci 103108c2ecf20Sopenharmony_cistatic void __net_exit devlink_pernet_pre_exit(struct net *net) 103118c2ecf20Sopenharmony_ci{ 103128c2ecf20Sopenharmony_ci struct devlink *devlink; 103138c2ecf20Sopenharmony_ci u32 actions_performed; 103148c2ecf20Sopenharmony_ci int err; 103158c2ecf20Sopenharmony_ci 103168c2ecf20Sopenharmony_ci /* In case network namespace is getting destroyed, reload 103178c2ecf20Sopenharmony_ci * all devlink instances from this namespace into init_net. 103188c2ecf20Sopenharmony_ci */ 103198c2ecf20Sopenharmony_ci mutex_lock(&devlink_mutex); 103208c2ecf20Sopenharmony_ci list_for_each_entry(devlink, &devlink_list, list) { 103218c2ecf20Sopenharmony_ci if (net_eq(devlink_net(devlink), net)) { 103228c2ecf20Sopenharmony_ci if (WARN_ON(!devlink_reload_supported(devlink->ops))) 103238c2ecf20Sopenharmony_ci continue; 103248c2ecf20Sopenharmony_ci err = devlink_reload(devlink, &init_net, 103258c2ecf20Sopenharmony_ci DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 103268c2ecf20Sopenharmony_ci DEVLINK_RELOAD_LIMIT_UNSPEC, 103278c2ecf20Sopenharmony_ci &actions_performed, NULL); 103288c2ecf20Sopenharmony_ci if (err && err != -EOPNOTSUPP) 103298c2ecf20Sopenharmony_ci pr_warn("Failed to reload devlink instance into init_net\n"); 103308c2ecf20Sopenharmony_ci } 103318c2ecf20Sopenharmony_ci } 103328c2ecf20Sopenharmony_ci mutex_unlock(&devlink_mutex); 103338c2ecf20Sopenharmony_ci} 103348c2ecf20Sopenharmony_ci 103358c2ecf20Sopenharmony_cistatic struct pernet_operations devlink_pernet_ops __net_initdata = { 103368c2ecf20Sopenharmony_ci .pre_exit = devlink_pernet_pre_exit, 103378c2ecf20Sopenharmony_ci}; 103388c2ecf20Sopenharmony_ci 103398c2ecf20Sopenharmony_cistatic int __init devlink_init(void) 103408c2ecf20Sopenharmony_ci{ 103418c2ecf20Sopenharmony_ci int err; 103428c2ecf20Sopenharmony_ci 103438c2ecf20Sopenharmony_ci err = genl_register_family(&devlink_nl_family); 103448c2ecf20Sopenharmony_ci if (err) 103458c2ecf20Sopenharmony_ci goto out; 103468c2ecf20Sopenharmony_ci err = register_pernet_subsys(&devlink_pernet_ops); 103478c2ecf20Sopenharmony_ci 103488c2ecf20Sopenharmony_ciout: 103498c2ecf20Sopenharmony_ci WARN_ON(err); 103508c2ecf20Sopenharmony_ci return err; 103518c2ecf20Sopenharmony_ci} 103528c2ecf20Sopenharmony_ci 103538c2ecf20Sopenharmony_cisubsys_initcall(devlink_init); 10354