162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* Copyright (c) 2016 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/etherdevice.h> 762306a36Sopenharmony_ci#include <linux/mutex.h> 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/notifier.h> 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/workqueue.h> 1262306a36Sopenharmony_ci#include <linux/xarray.h> 1362306a36Sopenharmony_ci#include <net/devlink.h> 1462306a36Sopenharmony_ci#include <net/net_namespace.h> 1562306a36Sopenharmony_ci#include <net/rtnetlink.h> 1662306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "netlink_gen.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define DEVLINK_REGISTERED XA_MARK_1 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ 2362306a36Sopenharmony_ci (__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct devlink_dev_stats { 2662306a36Sopenharmony_ci u32 reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE]; 2762306a36Sopenharmony_ci u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE]; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct devlink { 3162306a36Sopenharmony_ci u32 index; 3262306a36Sopenharmony_ci struct xarray ports; 3362306a36Sopenharmony_ci struct list_head rate_list; 3462306a36Sopenharmony_ci struct list_head sb_list; 3562306a36Sopenharmony_ci struct list_head dpipe_table_list; 3662306a36Sopenharmony_ci struct list_head resource_list; 3762306a36Sopenharmony_ci struct xarray params; 3862306a36Sopenharmony_ci struct list_head region_list; 3962306a36Sopenharmony_ci struct list_head reporter_list; 4062306a36Sopenharmony_ci struct devlink_dpipe_headers *dpipe_headers; 4162306a36Sopenharmony_ci struct list_head trap_list; 4262306a36Sopenharmony_ci struct list_head trap_group_list; 4362306a36Sopenharmony_ci struct list_head trap_policer_list; 4462306a36Sopenharmony_ci struct list_head linecard_list; 4562306a36Sopenharmony_ci const struct devlink_ops *ops; 4662306a36Sopenharmony_ci struct xarray snapshot_ids; 4762306a36Sopenharmony_ci struct devlink_dev_stats stats; 4862306a36Sopenharmony_ci struct device *dev; 4962306a36Sopenharmony_ci possible_net_t _net; 5062306a36Sopenharmony_ci /* Serializes access to devlink instance specific objects such as 5162306a36Sopenharmony_ci * port, sb, dpipe, resource, params, region, traps and more. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci struct mutex lock; 5462306a36Sopenharmony_ci struct lock_class_key lock_key; 5562306a36Sopenharmony_ci u8 reload_failed:1; 5662306a36Sopenharmony_ci refcount_t refcount; 5762306a36Sopenharmony_ci struct rcu_work rwork; 5862306a36Sopenharmony_ci char priv[] __aligned(NETDEV_ALIGN); 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciextern struct xarray devlinks; 6262306a36Sopenharmony_ciextern struct genl_family devlink_nl_family; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* devlink instances are open to the access from the user space after 6562306a36Sopenharmony_ci * devlink_register() call. Such logical barrier allows us to have certain 6662306a36Sopenharmony_ci * expectations related to locking. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * Before *_register() - we are in initialization stage and no parallel 6962306a36Sopenharmony_ci * access possible to the devlink instance. All drivers perform that phase 7062306a36Sopenharmony_ci * by implicitly holding device_lock. 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * After *_register() - users and driver can access devlink instance at 7362306a36Sopenharmony_ci * the same time. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci#define ASSERT_DEVLINK_REGISTERED(d) \ 7662306a36Sopenharmony_ci WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) 7762306a36Sopenharmony_ci#define ASSERT_DEVLINK_NOT_REGISTERED(d) \ 7862306a36Sopenharmony_ci WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Iterate over devlink pointers which were possible to get reference to. 8162306a36Sopenharmony_ci * devlink_put() needs to be called for each iterated devlink pointer 8262306a36Sopenharmony_ci * in loop body in order to release the reference. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci#define devlinks_xa_for_each_registered_get(net, index, devlink) \ 8562306a36Sopenharmony_ci for (index = 0; (devlink = devlinks_xa_find_get(net, &index)); index++) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic inline bool devl_is_registered(struct devlink *devlink) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci devl_assert_locked(devlink); 9262306a36Sopenharmony_ci return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Netlink */ 9662306a36Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_PORT BIT(0) 9762306a36Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum devlink_multicast_groups { 10062306a36Sopenharmony_ci DEVLINK_MCGRP_CONFIG, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* state held across netlink dumps */ 10462306a36Sopenharmony_cistruct devlink_nl_dump_state { 10562306a36Sopenharmony_ci unsigned long instance; 10662306a36Sopenharmony_ci int idx; 10762306a36Sopenharmony_ci union { 10862306a36Sopenharmony_ci /* DEVLINK_CMD_REGION_READ */ 10962306a36Sopenharmony_ci struct { 11062306a36Sopenharmony_ci u64 start_offset; 11162306a36Sopenharmony_ci }; 11262306a36Sopenharmony_ci /* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET */ 11362306a36Sopenharmony_ci struct { 11462306a36Sopenharmony_ci u64 dump_ts; 11562306a36Sopenharmony_ci }; 11662306a36Sopenharmony_ci }; 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_citypedef int devlink_nl_dump_one_func_t(struct sk_buff *msg, 12062306a36Sopenharmony_ci struct devlink *devlink, 12162306a36Sopenharmony_ci struct netlink_callback *cb, 12262306a36Sopenharmony_ci int flags); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct devlink * 12562306a36Sopenharmony_cidevlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ciint devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, 12862306a36Sopenharmony_ci devlink_nl_dump_one_func_t *dump_one); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic inline struct devlink_nl_dump_state * 13162306a36Sopenharmony_cidevlink_dump_state(struct netlink_callback *cb) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci NL_ASSERT_DUMP_CTX_FITS(struct devlink_nl_dump_state); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return (struct devlink_nl_dump_state *)cb->ctx; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline int 13962306a36Sopenharmony_cidevlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name)) 14262306a36Sopenharmony_ci return -EMSGSIZE; 14362306a36Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev))) 14462306a36Sopenharmony_ci return -EMSGSIZE; 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciint devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Notify */ 15162306a36Sopenharmony_civoid devlink_notify_register(struct devlink *devlink); 15262306a36Sopenharmony_civoid devlink_notify_unregister(struct devlink *devlink); 15362306a36Sopenharmony_civoid devlink_ports_notify_register(struct devlink *devlink); 15462306a36Sopenharmony_civoid devlink_ports_notify_unregister(struct devlink *devlink); 15562306a36Sopenharmony_civoid devlink_params_notify_register(struct devlink *devlink); 15662306a36Sopenharmony_civoid devlink_params_notify_unregister(struct devlink *devlink); 15762306a36Sopenharmony_civoid devlink_regions_notify_register(struct devlink *devlink); 15862306a36Sopenharmony_civoid devlink_regions_notify_unregister(struct devlink *devlink); 15962306a36Sopenharmony_civoid devlink_trap_policers_notify_register(struct devlink *devlink); 16062306a36Sopenharmony_civoid devlink_trap_policers_notify_unregister(struct devlink *devlink); 16162306a36Sopenharmony_civoid devlink_trap_groups_notify_register(struct devlink *devlink); 16262306a36Sopenharmony_civoid devlink_trap_groups_notify_unregister(struct devlink *devlink); 16362306a36Sopenharmony_civoid devlink_traps_notify_register(struct devlink *devlink); 16462306a36Sopenharmony_civoid devlink_traps_notify_unregister(struct devlink *devlink); 16562306a36Sopenharmony_civoid devlink_rates_notify_register(struct devlink *devlink); 16662306a36Sopenharmony_civoid devlink_rates_notify_unregister(struct devlink *devlink); 16762306a36Sopenharmony_civoid devlink_linecards_notify_register(struct devlink *devlink); 16862306a36Sopenharmony_civoid devlink_linecards_notify_unregister(struct devlink *devlink); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Ports */ 17162306a36Sopenharmony_ci#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port) \ 17262306a36Sopenharmony_ci WARN_ON_ONCE(!(devlink_port)->initialized) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct devlink_port *devlink_port_get_by_index(struct devlink *devlink, 17562306a36Sopenharmony_ci unsigned int port_index); 17662306a36Sopenharmony_ciint devlink_port_netdevice_event(struct notifier_block *nb, 17762306a36Sopenharmony_ci unsigned long event, void *ptr); 17862306a36Sopenharmony_cistruct devlink_port * 17962306a36Sopenharmony_cidevlink_port_get_from_info(struct devlink *devlink, struct genl_info *info); 18062306a36Sopenharmony_cistruct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink, 18162306a36Sopenharmony_ci struct nlattr **attrs); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Reload */ 18462306a36Sopenharmony_cibool devlink_reload_actions_valid(const struct devlink_ops *ops); 18562306a36Sopenharmony_ciint devlink_reload(struct devlink *devlink, struct net *dest_net, 18662306a36Sopenharmony_ci enum devlink_reload_action action, 18762306a36Sopenharmony_ci enum devlink_reload_limit limit, 18862306a36Sopenharmony_ci u32 *actions_performed, struct netlink_ext_ack *extack); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic inline bool devlink_reload_supported(const struct devlink_ops *ops) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci return ops->reload_down && ops->reload_up; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* Params */ 19662306a36Sopenharmony_civoid devlink_params_driverinit_load_new(struct devlink *devlink); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* Resources */ 19962306a36Sopenharmony_cistruct devlink_resource; 20062306a36Sopenharmony_ciint devlink_resources_validate(struct devlink *devlink, 20162306a36Sopenharmony_ci struct devlink_resource *resource, 20262306a36Sopenharmony_ci struct genl_info *info); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* Rates */ 20562306a36Sopenharmony_ciint devlink_rate_nodes_check(struct devlink *devlink, u16 mode, 20662306a36Sopenharmony_ci struct netlink_ext_ack *extack); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* Linecards */ 20962306a36Sopenharmony_cistruct devlink_linecard { 21062306a36Sopenharmony_ci struct list_head list; 21162306a36Sopenharmony_ci struct devlink *devlink; 21262306a36Sopenharmony_ci unsigned int index; 21362306a36Sopenharmony_ci const struct devlink_linecard_ops *ops; 21462306a36Sopenharmony_ci void *priv; 21562306a36Sopenharmony_ci enum devlink_linecard_state state; 21662306a36Sopenharmony_ci struct mutex state_lock; /* Protects state */ 21762306a36Sopenharmony_ci const char *type; 21862306a36Sopenharmony_ci struct devlink_linecard_type *types; 21962306a36Sopenharmony_ci unsigned int types_count; 22062306a36Sopenharmony_ci struct devlink *nested_devlink; 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* Devlink nl cmds */ 22462306a36Sopenharmony_ciint devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info); 22562306a36Sopenharmony_ciint devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info); 22662306a36Sopenharmony_ciint devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info); 22762306a36Sopenharmony_ciint devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info); 22862306a36Sopenharmony_ciint devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info); 22962306a36Sopenharmony_ciint devlink_nl_cmd_port_set_doit(struct sk_buff *skb, struct genl_info *info); 23062306a36Sopenharmony_ciint devlink_nl_cmd_port_split_doit(struct sk_buff *skb, struct genl_info *info); 23162306a36Sopenharmony_ciint devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, 23262306a36Sopenharmony_ci struct genl_info *info); 23362306a36Sopenharmony_ciint devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct genl_info *info); 23462306a36Sopenharmony_ciint devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct genl_info *info); 23562306a36Sopenharmony_ciint devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info); 23662306a36Sopenharmony_ciint devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb, 23762306a36Sopenharmony_ci struct genl_info *info); 23862306a36Sopenharmony_ciint devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb, 23962306a36Sopenharmony_ci struct genl_info *info); 24062306a36Sopenharmony_ciint devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb, 24162306a36Sopenharmony_ci struct genl_info *info); 24262306a36Sopenharmony_ciint devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb, 24362306a36Sopenharmony_ci struct genl_info *info); 24462306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb, struct genl_info *info); 24562306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb, 24662306a36Sopenharmony_ci struct genl_info *info); 24762306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb, 24862306a36Sopenharmony_ci struct genl_info *info); 24962306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb, 25062306a36Sopenharmony_ci struct genl_info *info); 25162306a36Sopenharmony_ciint devlink_nl_cmd_resource_set(struct sk_buff *skb, struct genl_info *info); 25262306a36Sopenharmony_ciint devlink_nl_cmd_resource_dump(struct sk_buff *skb, struct genl_info *info); 25362306a36Sopenharmony_ciint devlink_nl_cmd_param_set_doit(struct sk_buff *skb, struct genl_info *info); 25462306a36Sopenharmony_ciint devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg, 25562306a36Sopenharmony_ci struct netlink_callback *cb); 25662306a36Sopenharmony_ciint devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb, 25762306a36Sopenharmony_ci struct genl_info *info); 25862306a36Sopenharmony_ciint devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb, 25962306a36Sopenharmony_ci struct genl_info *info); 26062306a36Sopenharmony_ciint devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info); 26162306a36Sopenharmony_ciint devlink_nl_cmd_region_del(struct sk_buff *skb, struct genl_info *info); 26262306a36Sopenharmony_ciint devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, 26362306a36Sopenharmony_ci struct netlink_callback *cb); 26462306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb, 26562306a36Sopenharmony_ci struct genl_info *info); 26662306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb, 26762306a36Sopenharmony_ci struct genl_info *info); 26862306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb, 26962306a36Sopenharmony_ci struct genl_info *info); 27062306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb, 27162306a36Sopenharmony_ci struct netlink_callback *cb); 27262306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb, 27362306a36Sopenharmony_ci struct genl_info *info); 27462306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb, 27562306a36Sopenharmony_ci struct genl_info *info); 27662306a36Sopenharmony_ciint devlink_nl_cmd_trap_set_doit(struct sk_buff *skb, struct genl_info *info); 27762306a36Sopenharmony_ciint devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb, 27862306a36Sopenharmony_ci struct genl_info *info); 27962306a36Sopenharmony_ciint devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb, 28062306a36Sopenharmony_ci struct genl_info *info); 28162306a36Sopenharmony_ciint devlink_nl_cmd_rate_set_doit(struct sk_buff *skb, struct genl_info *info); 28262306a36Sopenharmony_ciint devlink_nl_cmd_rate_new_doit(struct sk_buff *skb, struct genl_info *info); 28362306a36Sopenharmony_ciint devlink_nl_cmd_rate_del_doit(struct sk_buff *skb, struct genl_info *info); 28462306a36Sopenharmony_ciint devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, 28562306a36Sopenharmony_ci struct genl_info *info); 286