162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <trace/events/devlink.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "devl_internal.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct devlink_stats { 1262306a36Sopenharmony_ci u64_stats_t rx_bytes; 1362306a36Sopenharmony_ci u64_stats_t rx_packets; 1462306a36Sopenharmony_ci struct u64_stats_sync syncp; 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/** 1862306a36Sopenharmony_ci * struct devlink_trap_policer_item - Packet trap policer attributes. 1962306a36Sopenharmony_ci * @policer: Immutable packet trap policer attributes. 2062306a36Sopenharmony_ci * @rate: Rate in packets / sec. 2162306a36Sopenharmony_ci * @burst: Burst size in packets. 2262306a36Sopenharmony_ci * @list: trap_policer_list member. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Describes packet trap policer attributes. Created by devlink during trap 2562306a36Sopenharmony_ci * policer registration. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistruct devlink_trap_policer_item { 2862306a36Sopenharmony_ci const struct devlink_trap_policer *policer; 2962306a36Sopenharmony_ci u64 rate; 3062306a36Sopenharmony_ci u64 burst; 3162306a36Sopenharmony_ci struct list_head list; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/** 3562306a36Sopenharmony_ci * struct devlink_trap_group_item - Packet trap group attributes. 3662306a36Sopenharmony_ci * @group: Immutable packet trap group attributes. 3762306a36Sopenharmony_ci * @policer_item: Associated policer item. Can be NULL. 3862306a36Sopenharmony_ci * @list: trap_group_list member. 3962306a36Sopenharmony_ci * @stats: Trap group statistics. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Describes packet trap group attributes. Created by devlink during trap 4262306a36Sopenharmony_ci * group registration. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistruct devlink_trap_group_item { 4562306a36Sopenharmony_ci const struct devlink_trap_group *group; 4662306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 4762306a36Sopenharmony_ci struct list_head list; 4862306a36Sopenharmony_ci struct devlink_stats __percpu *stats; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * struct devlink_trap_item - Packet trap attributes. 5362306a36Sopenharmony_ci * @trap: Immutable packet trap attributes. 5462306a36Sopenharmony_ci * @group_item: Associated group item. 5562306a36Sopenharmony_ci * @list: trap_list member. 5662306a36Sopenharmony_ci * @action: Trap action. 5762306a36Sopenharmony_ci * @stats: Trap statistics. 5862306a36Sopenharmony_ci * @priv: Driver private information. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Describes both mutable and immutable packet trap attributes. Created by 6162306a36Sopenharmony_ci * devlink during trap registration and used for all trap related operations. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistruct devlink_trap_item { 6462306a36Sopenharmony_ci const struct devlink_trap *trap; 6562306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 6662306a36Sopenharmony_ci struct list_head list; 6762306a36Sopenharmony_ci enum devlink_trap_action action; 6862306a36Sopenharmony_ci struct devlink_stats __percpu *stats; 6962306a36Sopenharmony_ci void *priv; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic struct devlink_trap_policer_item * 7362306a36Sopenharmony_cidevlink_trap_policer_item_lookup(struct devlink *devlink, u32 id) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci list_for_each_entry(policer_item, &devlink->trap_policer_list, list) { 7862306a36Sopenharmony_ci if (policer_item->policer->id == id) 7962306a36Sopenharmony_ci return policer_item; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return NULL; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic struct devlink_trap_item * 8662306a36Sopenharmony_cidevlink_trap_item_lookup(struct devlink *devlink, const char *name) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 9162306a36Sopenharmony_ci if (!strcmp(trap_item->trap->name, name)) 9262306a36Sopenharmony_ci return trap_item; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return NULL; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct devlink_trap_item * 9962306a36Sopenharmony_cidevlink_trap_item_get_from_info(struct devlink *devlink, 10062306a36Sopenharmony_ci struct genl_info *info) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct nlattr *attr; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_NAME]) 10562306a36Sopenharmony_ci return NULL; 10662306a36Sopenharmony_ci attr = info->attrs[DEVLINK_ATTR_TRAP_NAME]; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return devlink_trap_item_lookup(devlink, nla_data(attr)); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int 11262306a36Sopenharmony_cidevlink_trap_action_get_from_info(struct genl_info *info, 11362306a36Sopenharmony_ci enum devlink_trap_action *p_trap_action) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u8 val; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]); 11862306a36Sopenharmony_ci switch (val) { 11962306a36Sopenharmony_ci case DEVLINK_TRAP_ACTION_DROP: 12062306a36Sopenharmony_ci case DEVLINK_TRAP_ACTION_TRAP: 12162306a36Sopenharmony_ci case DEVLINK_TRAP_ACTION_MIRROR: 12262306a36Sopenharmony_ci *p_trap_action = val; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci default: 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int devlink_trap_metadata_put(struct sk_buff *msg, 13262306a36Sopenharmony_ci const struct devlink_trap *trap) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct nlattr *attr; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA); 13762306a36Sopenharmony_ci if (!attr) 13862306a36Sopenharmony_ci return -EMSGSIZE; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) && 14162306a36Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT)) 14262306a36Sopenharmony_ci goto nla_put_failure; 14362306a36Sopenharmony_ci if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) && 14462306a36Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE)) 14562306a36Sopenharmony_ci goto nla_put_failure; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci nla_nest_end(msg, attr); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cinla_put_failure: 15262306a36Sopenharmony_ci nla_nest_cancel(msg, attr); 15362306a36Sopenharmony_ci return -EMSGSIZE; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats, 15762306a36Sopenharmony_ci struct devlink_stats *stats) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 16262306a36Sopenharmony_ci for_each_possible_cpu(i) { 16362306a36Sopenharmony_ci struct devlink_stats *cpu_stats; 16462306a36Sopenharmony_ci u64 rx_packets, rx_bytes; 16562306a36Sopenharmony_ci unsigned int start; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci cpu_stats = per_cpu_ptr(trap_stats, i); 16862306a36Sopenharmony_ci do { 16962306a36Sopenharmony_ci start = u64_stats_fetch_begin(&cpu_stats->syncp); 17062306a36Sopenharmony_ci rx_packets = u64_stats_read(&cpu_stats->rx_packets); 17162306a36Sopenharmony_ci rx_bytes = u64_stats_read(&cpu_stats->rx_bytes); 17262306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci u64_stats_add(&stats->rx_packets, rx_packets); 17562306a36Sopenharmony_ci u64_stats_add(&stats->rx_bytes, rx_bytes); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int 18062306a36Sopenharmony_cidevlink_trap_group_stats_put(struct sk_buff *msg, 18162306a36Sopenharmony_ci struct devlink_stats __percpu *trap_stats) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct devlink_stats stats; 18462306a36Sopenharmony_ci struct nlattr *attr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci devlink_trap_stats_read(trap_stats, &stats); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_STATS); 18962306a36Sopenharmony_ci if (!attr) 19062306a36Sopenharmony_ci return -EMSGSIZE; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS, 19362306a36Sopenharmony_ci u64_stats_read(&stats.rx_packets), 19462306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 19562306a36Sopenharmony_ci goto nla_put_failure; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES, 19862306a36Sopenharmony_ci u64_stats_read(&stats.rx_bytes), 19962306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 20062306a36Sopenharmony_ci goto nla_put_failure; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci nla_nest_end(msg, attr); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cinla_put_failure: 20762306a36Sopenharmony_ci nla_nest_cancel(msg, attr); 20862306a36Sopenharmony_ci return -EMSGSIZE; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink, 21262306a36Sopenharmony_ci const struct devlink_trap_item *trap_item) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct devlink_stats stats; 21562306a36Sopenharmony_ci struct nlattr *attr; 21662306a36Sopenharmony_ci u64 drops = 0; 21762306a36Sopenharmony_ci int err; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (devlink->ops->trap_drop_counter_get) { 22062306a36Sopenharmony_ci err = devlink->ops->trap_drop_counter_get(devlink, 22162306a36Sopenharmony_ci trap_item->trap, 22262306a36Sopenharmony_ci &drops); 22362306a36Sopenharmony_ci if (err) 22462306a36Sopenharmony_ci return err; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci devlink_trap_stats_read(trap_item->stats, &stats); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_STATS); 23062306a36Sopenharmony_ci if (!attr) 23162306a36Sopenharmony_ci return -EMSGSIZE; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (devlink->ops->trap_drop_counter_get && 23462306a36Sopenharmony_ci nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops, 23562306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 23662306a36Sopenharmony_ci goto nla_put_failure; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS, 23962306a36Sopenharmony_ci u64_stats_read(&stats.rx_packets), 24062306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 24162306a36Sopenharmony_ci goto nla_put_failure; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES, 24462306a36Sopenharmony_ci u64_stats_read(&stats.rx_bytes), 24562306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 24662306a36Sopenharmony_ci goto nla_put_failure; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci nla_nest_end(msg, attr); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cinla_put_failure: 25362306a36Sopenharmony_ci nla_nest_cancel(msg, attr); 25462306a36Sopenharmony_ci return -EMSGSIZE; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink, 25862306a36Sopenharmony_ci const struct devlink_trap_item *trap_item, 25962306a36Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 26062306a36Sopenharmony_ci int flags) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct devlink_trap_group_item *group_item = trap_item->group_item; 26362306a36Sopenharmony_ci void *hdr; 26462306a36Sopenharmony_ci int err; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 26762306a36Sopenharmony_ci if (!hdr) 26862306a36Sopenharmony_ci return -EMSGSIZE; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 27162306a36Sopenharmony_ci goto nla_put_failure; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME, 27462306a36Sopenharmony_ci group_item->group->name)) 27562306a36Sopenharmony_ci goto nla_put_failure; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name)) 27862306a36Sopenharmony_ci goto nla_put_failure; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type)) 28162306a36Sopenharmony_ci goto nla_put_failure; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (trap_item->trap->generic && 28462306a36Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC)) 28562306a36Sopenharmony_ci goto nla_put_failure; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action)) 28862306a36Sopenharmony_ci goto nla_put_failure; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci err = devlink_trap_metadata_put(msg, trap_item->trap); 29162306a36Sopenharmony_ci if (err) 29262306a36Sopenharmony_ci goto nla_put_failure; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci err = devlink_trap_stats_put(msg, devlink, trap_item); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci goto nla_put_failure; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci genlmsg_end(msg, hdr); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cinla_put_failure: 30362306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 30462306a36Sopenharmony_ci return -EMSGSIZE; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciint devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 31062306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 31162306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 31262306a36Sopenharmony_ci struct sk_buff *msg; 31362306a36Sopenharmony_ci int err; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (list_empty(&devlink->trap_list)) 31662306a36Sopenharmony_ci return -EOPNOTSUPP; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci trap_item = devlink_trap_item_get_from_info(devlink, info); 31962306a36Sopenharmony_ci if (!trap_item) { 32062306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap"); 32162306a36Sopenharmony_ci return -ENOENT; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 32562306a36Sopenharmony_ci if (!msg) 32662306a36Sopenharmony_ci return -ENOMEM; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, 32962306a36Sopenharmony_ci DEVLINK_CMD_TRAP_NEW, info->snd_portid, 33062306a36Sopenharmony_ci info->snd_seq, 0); 33162306a36Sopenharmony_ci if (err) 33262306a36Sopenharmony_ci goto err_trap_fill; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return genlmsg_reply(msg, info); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cierr_trap_fill: 33762306a36Sopenharmony_ci nlmsg_free(msg); 33862306a36Sopenharmony_ci return err; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int devlink_nl_trap_get_dump_one(struct sk_buff *msg, 34262306a36Sopenharmony_ci struct devlink *devlink, 34362306a36Sopenharmony_ci struct netlink_callback *cb, int flags) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct devlink_nl_dump_state *state = devlink_dump_state(cb); 34662306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 34762306a36Sopenharmony_ci int idx = 0; 34862306a36Sopenharmony_ci int err = 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 35162306a36Sopenharmony_ci if (idx < state->idx) { 35262306a36Sopenharmony_ci idx++; 35362306a36Sopenharmony_ci continue; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, 35662306a36Sopenharmony_ci DEVLINK_CMD_TRAP_NEW, 35762306a36Sopenharmony_ci NETLINK_CB(cb->skb).portid, 35862306a36Sopenharmony_ci cb->nlh->nlmsg_seq, flags); 35962306a36Sopenharmony_ci if (err) { 36062306a36Sopenharmony_ci state->idx = idx; 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci idx++; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ciint devlink_nl_trap_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return devlink_nl_dumpit(skb, cb, devlink_nl_trap_get_dump_one); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int __devlink_trap_action_set(struct devlink *devlink, 37562306a36Sopenharmony_ci struct devlink_trap_item *trap_item, 37662306a36Sopenharmony_ci enum devlink_trap_action trap_action, 37762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int err; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (trap_item->action != trap_action && 38262306a36Sopenharmony_ci trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) { 38362306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Cannot change action of non-drop traps. Skipping"); 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci err = devlink->ops->trap_action_set(devlink, trap_item->trap, 38862306a36Sopenharmony_ci trap_action, extack); 38962306a36Sopenharmony_ci if (err) 39062306a36Sopenharmony_ci return err; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci trap_item->action = trap_action; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int devlink_trap_action_set(struct devlink *devlink, 39862306a36Sopenharmony_ci struct devlink_trap_item *trap_item, 39962306a36Sopenharmony_ci struct genl_info *info) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci enum devlink_trap_action trap_action; 40262306a36Sopenharmony_ci int err; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION]) 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci err = devlink_trap_action_get_from_info(info, &trap_action); 40862306a36Sopenharmony_ci if (err) { 40962306a36Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Invalid trap action"); 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return __devlink_trap_action_set(devlink, trap_item, trap_action, 41462306a36Sopenharmony_ci info->extack); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint devlink_nl_cmd_trap_set_doit(struct sk_buff *skb, struct genl_info *info) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 42062306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 42162306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (list_empty(&devlink->trap_list)) 42462306a36Sopenharmony_ci return -EOPNOTSUPP; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci trap_item = devlink_trap_item_get_from_info(devlink, info); 42762306a36Sopenharmony_ci if (!trap_item) { 42862306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap"); 42962306a36Sopenharmony_ci return -ENOENT; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return devlink_trap_action_set(devlink, trap_item, info); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic struct devlink_trap_group_item * 43662306a36Sopenharmony_cidevlink_trap_group_item_lookup(struct devlink *devlink, const char *name) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) { 44162306a36Sopenharmony_ci if (!strcmp(group_item->group->name, name)) 44262306a36Sopenharmony_ci return group_item; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return NULL; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic struct devlink_trap_group_item * 44962306a36Sopenharmony_cidevlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) { 45462306a36Sopenharmony_ci if (group_item->group->id == id) 45562306a36Sopenharmony_ci return group_item; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return NULL; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic struct devlink_trap_group_item * 46262306a36Sopenharmony_cidevlink_trap_group_item_get_from_info(struct devlink *devlink, 46362306a36Sopenharmony_ci struct genl_info *info) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci char *name; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]) 46862306a36Sopenharmony_ci return NULL; 46962306a36Sopenharmony_ci name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return devlink_trap_group_item_lookup(devlink, name); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int 47562306a36Sopenharmony_cidevlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink, 47662306a36Sopenharmony_ci const struct devlink_trap_group_item *group_item, 47762306a36Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 47862306a36Sopenharmony_ci int flags) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci void *hdr; 48162306a36Sopenharmony_ci int err; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 48462306a36Sopenharmony_ci if (!hdr) 48562306a36Sopenharmony_ci return -EMSGSIZE; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 48862306a36Sopenharmony_ci goto nla_put_failure; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME, 49162306a36Sopenharmony_ci group_item->group->name)) 49262306a36Sopenharmony_ci goto nla_put_failure; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (group_item->group->generic && 49562306a36Sopenharmony_ci nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC)) 49662306a36Sopenharmony_ci goto nla_put_failure; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (group_item->policer_item && 49962306a36Sopenharmony_ci nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID, 50062306a36Sopenharmony_ci group_item->policer_item->policer->id)) 50162306a36Sopenharmony_ci goto nla_put_failure; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci err = devlink_trap_group_stats_put(msg, group_item->stats); 50462306a36Sopenharmony_ci if (err) 50562306a36Sopenharmony_ci goto nla_put_failure; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci genlmsg_end(msg, hdr); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cinla_put_failure: 51262306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 51362306a36Sopenharmony_ci return -EMSGSIZE; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciint devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 51962306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 52062306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 52162306a36Sopenharmony_ci struct sk_buff *msg; 52262306a36Sopenharmony_ci int err; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (list_empty(&devlink->trap_group_list)) 52562306a36Sopenharmony_ci return -EOPNOTSUPP; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci group_item = devlink_trap_group_item_get_from_info(devlink, info); 52862306a36Sopenharmony_ci if (!group_item) { 52962306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap group"); 53062306a36Sopenharmony_ci return -ENOENT; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 53462306a36Sopenharmony_ci if (!msg) 53562306a36Sopenharmony_ci return -ENOMEM; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, group_item, 53862306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW, 53962306a36Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 54062306a36Sopenharmony_ci if (err) 54162306a36Sopenharmony_ci goto err_trap_group_fill; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci return genlmsg_reply(msg, info); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cierr_trap_group_fill: 54662306a36Sopenharmony_ci nlmsg_free(msg); 54762306a36Sopenharmony_ci return err; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int devlink_nl_trap_group_get_dump_one(struct sk_buff *msg, 55162306a36Sopenharmony_ci struct devlink *devlink, 55262306a36Sopenharmony_ci struct netlink_callback *cb, 55362306a36Sopenharmony_ci int flags) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct devlink_nl_dump_state *state = devlink_dump_state(cb); 55662306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 55762306a36Sopenharmony_ci int idx = 0; 55862306a36Sopenharmony_ci int err = 0; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) { 56162306a36Sopenharmony_ci if (idx < state->idx) { 56262306a36Sopenharmony_ci idx++; 56362306a36Sopenharmony_ci continue; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, group_item, 56662306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW, 56762306a36Sopenharmony_ci NETLINK_CB(cb->skb).portid, 56862306a36Sopenharmony_ci cb->nlh->nlmsg_seq, flags); 56962306a36Sopenharmony_ci if (err) { 57062306a36Sopenharmony_ci state->idx = idx; 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci idx++; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return err; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciint devlink_nl_trap_group_get_dumpit(struct sk_buff *skb, 58062306a36Sopenharmony_ci struct netlink_callback *cb) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci return devlink_nl_dumpit(skb, cb, devlink_nl_trap_group_get_dump_one); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int 58662306a36Sopenharmony_ci__devlink_trap_group_action_set(struct devlink *devlink, 58762306a36Sopenharmony_ci struct devlink_trap_group_item *group_item, 58862306a36Sopenharmony_ci enum devlink_trap_action trap_action, 58962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci const char *group_name = group_item->group->name; 59262306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 59362306a36Sopenharmony_ci int err; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (devlink->ops->trap_group_action_set) { 59662306a36Sopenharmony_ci err = devlink->ops->trap_group_action_set(devlink, group_item->group, 59762306a36Sopenharmony_ci trap_action, extack); 59862306a36Sopenharmony_ci if (err) 59962306a36Sopenharmony_ci return err; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 60262306a36Sopenharmony_ci if (strcmp(trap_item->group_item->group->name, group_name)) 60362306a36Sopenharmony_ci continue; 60462306a36Sopenharmony_ci if (trap_item->action != trap_action && 60562306a36Sopenharmony_ci trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) 60662306a36Sopenharmony_ci continue; 60762306a36Sopenharmony_ci trap_item->action = trap_action; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) { 61462306a36Sopenharmony_ci if (strcmp(trap_item->group_item->group->name, group_name)) 61562306a36Sopenharmony_ci continue; 61662306a36Sopenharmony_ci err = __devlink_trap_action_set(devlink, trap_item, 61762306a36Sopenharmony_ci trap_action, extack); 61862306a36Sopenharmony_ci if (err) 61962306a36Sopenharmony_ci return err; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int 62662306a36Sopenharmony_cidevlink_trap_group_action_set(struct devlink *devlink, 62762306a36Sopenharmony_ci struct devlink_trap_group_item *group_item, 62862306a36Sopenharmony_ci struct genl_info *info, bool *p_modified) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci enum devlink_trap_action trap_action; 63162306a36Sopenharmony_ci int err; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION]) 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci err = devlink_trap_action_get_from_info(info, &trap_action); 63762306a36Sopenharmony_ci if (err) { 63862306a36Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Invalid trap action"); 63962306a36Sopenharmony_ci return -EINVAL; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci err = __devlink_trap_group_action_set(devlink, group_item, trap_action, 64362306a36Sopenharmony_ci info->extack); 64462306a36Sopenharmony_ci if (err) 64562306a36Sopenharmony_ci return err; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci *p_modified = true; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int devlink_trap_group_set(struct devlink *devlink, 65362306a36Sopenharmony_ci struct devlink_trap_group_item *group_item, 65462306a36Sopenharmony_ci struct genl_info *info) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 65762306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 65862306a36Sopenharmony_ci const struct devlink_trap_policer *policer; 65962306a36Sopenharmony_ci struct nlattr **attrs = info->attrs; 66062306a36Sopenharmony_ci u32 policer_id; 66162306a36Sopenharmony_ci int err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!devlink->ops->trap_group_set) 66762306a36Sopenharmony_ci return -EOPNOTSUPP; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]); 67062306a36Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, policer_id); 67162306a36Sopenharmony_ci if (policer_id && !policer_item) { 67262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap policer"); 67362306a36Sopenharmony_ci return -ENOENT; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci policer = policer_item ? policer_item->policer : NULL; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci err = devlink->ops->trap_group_set(devlink, group_item->group, policer, 67862306a36Sopenharmony_ci extack); 67962306a36Sopenharmony_ci if (err) 68062306a36Sopenharmony_ci return err; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci group_item->policer_item = policer_item; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ciint devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb, 68862306a36Sopenharmony_ci struct genl_info *info) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 69162306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 69262306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 69362306a36Sopenharmony_ci bool modified = false; 69462306a36Sopenharmony_ci int err; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (list_empty(&devlink->trap_group_list)) 69762306a36Sopenharmony_ci return -EOPNOTSUPP; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci group_item = devlink_trap_group_item_get_from_info(devlink, info); 70062306a36Sopenharmony_ci if (!group_item) { 70162306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap group"); 70262306a36Sopenharmony_ci return -ENOENT; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci err = devlink_trap_group_action_set(devlink, group_item, info, 70662306a36Sopenharmony_ci &modified); 70762306a36Sopenharmony_ci if (err) 70862306a36Sopenharmony_ci return err; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci err = devlink_trap_group_set(devlink, group_item, info); 71162306a36Sopenharmony_ci if (err) 71262306a36Sopenharmony_ci goto err_trap_group_set; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return 0; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cierr_trap_group_set: 71762306a36Sopenharmony_ci if (modified) 71862306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Trap group set failed, but some changes were committed already"); 71962306a36Sopenharmony_ci return err; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic struct devlink_trap_policer_item * 72362306a36Sopenharmony_cidevlink_trap_policer_item_get_from_info(struct devlink *devlink, 72462306a36Sopenharmony_ci struct genl_info *info) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci u32 id; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) 72962306a36Sopenharmony_ci return NULL; 73062306a36Sopenharmony_ci id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return devlink_trap_policer_item_lookup(devlink, id); 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic int 73662306a36Sopenharmony_cidevlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink, 73762306a36Sopenharmony_ci const struct devlink_trap_policer *policer) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct nlattr *attr; 74062306a36Sopenharmony_ci u64 drops; 74162306a36Sopenharmony_ci int err; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (!devlink->ops->trap_policer_counter_get) 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops); 74762306a36Sopenharmony_ci if (err) 74862306a36Sopenharmony_ci return err; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci attr = nla_nest_start(msg, DEVLINK_ATTR_STATS); 75162306a36Sopenharmony_ci if (!attr) 75262306a36Sopenharmony_ci return -EMSGSIZE; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops, 75562306a36Sopenharmony_ci DEVLINK_ATTR_PAD)) 75662306a36Sopenharmony_ci goto nla_put_failure; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci nla_nest_end(msg, attr); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cinla_put_failure: 76362306a36Sopenharmony_ci nla_nest_cancel(msg, attr); 76462306a36Sopenharmony_ci return -EMSGSIZE; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int 76862306a36Sopenharmony_cidevlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink, 76962306a36Sopenharmony_ci const struct devlink_trap_policer_item *policer_item, 77062306a36Sopenharmony_ci enum devlink_command cmd, u32 portid, u32 seq, 77162306a36Sopenharmony_ci int flags) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci void *hdr; 77462306a36Sopenharmony_ci int err; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 77762306a36Sopenharmony_ci if (!hdr) 77862306a36Sopenharmony_ci return -EMSGSIZE; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (devlink_nl_put_handle(msg, devlink)) 78162306a36Sopenharmony_ci goto nla_put_failure; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID, 78462306a36Sopenharmony_ci policer_item->policer->id)) 78562306a36Sopenharmony_ci goto nla_put_failure; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE, 78862306a36Sopenharmony_ci policer_item->rate, DEVLINK_ATTR_PAD)) 78962306a36Sopenharmony_ci goto nla_put_failure; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST, 79262306a36Sopenharmony_ci policer_item->burst, DEVLINK_ATTR_PAD)) 79362306a36Sopenharmony_ci goto nla_put_failure; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci err = devlink_trap_policer_stats_put(msg, devlink, 79662306a36Sopenharmony_ci policer_item->policer); 79762306a36Sopenharmony_ci if (err) 79862306a36Sopenharmony_ci goto nla_put_failure; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci genlmsg_end(msg, hdr); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cinla_put_failure: 80562306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 80662306a36Sopenharmony_ci return -EMSGSIZE; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ciint devlink_nl_trap_policer_get_doit(struct sk_buff *skb, 81062306a36Sopenharmony_ci struct genl_info *info) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 81362306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 81462306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 81562306a36Sopenharmony_ci struct sk_buff *msg; 81662306a36Sopenharmony_ci int err; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (list_empty(&devlink->trap_policer_list)) 81962306a36Sopenharmony_ci return -EOPNOTSUPP; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci policer_item = devlink_trap_policer_item_get_from_info(devlink, info); 82262306a36Sopenharmony_ci if (!policer_item) { 82362306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap policer"); 82462306a36Sopenharmony_ci return -ENOENT; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 82862306a36Sopenharmony_ci if (!msg) 82962306a36Sopenharmony_ci return -ENOMEM; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, 83262306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW, 83362306a36Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 83462306a36Sopenharmony_ci if (err) 83562306a36Sopenharmony_ci goto err_trap_policer_fill; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return genlmsg_reply(msg, info); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cierr_trap_policer_fill: 84062306a36Sopenharmony_ci nlmsg_free(msg); 84162306a36Sopenharmony_ci return err; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int devlink_nl_trap_policer_get_dump_one(struct sk_buff *msg, 84562306a36Sopenharmony_ci struct devlink *devlink, 84662306a36Sopenharmony_ci struct netlink_callback *cb, 84762306a36Sopenharmony_ci int flags) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct devlink_nl_dump_state *state = devlink_dump_state(cb); 85062306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 85162306a36Sopenharmony_ci int idx = 0; 85262306a36Sopenharmony_ci int err = 0; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci list_for_each_entry(policer_item, &devlink->trap_policer_list, list) { 85562306a36Sopenharmony_ci if (idx < state->idx) { 85662306a36Sopenharmony_ci idx++; 85762306a36Sopenharmony_ci continue; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, 86062306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW, 86162306a36Sopenharmony_ci NETLINK_CB(cb->skb).portid, 86262306a36Sopenharmony_ci cb->nlh->nlmsg_seq, flags); 86362306a36Sopenharmony_ci if (err) { 86462306a36Sopenharmony_ci state->idx = idx; 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci idx++; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci return err; 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ciint devlink_nl_trap_policer_get_dumpit(struct sk_buff *skb, 87462306a36Sopenharmony_ci struct netlink_callback *cb) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci return devlink_nl_dumpit(skb, cb, devlink_nl_trap_policer_get_dump_one); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic int 88062306a36Sopenharmony_cidevlink_trap_policer_set(struct devlink *devlink, 88162306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item, 88262306a36Sopenharmony_ci struct genl_info *info) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 88562306a36Sopenharmony_ci struct nlattr **attrs = info->attrs; 88662306a36Sopenharmony_ci u64 rate, burst; 88762306a36Sopenharmony_ci int err; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci rate = policer_item->rate; 89062306a36Sopenharmony_ci burst = policer_item->burst; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]) 89362306a36Sopenharmony_ci rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]) 89662306a36Sopenharmony_ci burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (rate < policer_item->policer->min_rate) { 89962306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Policer rate lower than limit"); 90062306a36Sopenharmony_ci return -EINVAL; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (rate > policer_item->policer->max_rate) { 90462306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Policer rate higher than limit"); 90562306a36Sopenharmony_ci return -EINVAL; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (burst < policer_item->policer->min_burst) { 90962306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Policer burst size lower than limit"); 91062306a36Sopenharmony_ci return -EINVAL; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (burst > policer_item->policer->max_burst) { 91462306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Policer burst size higher than limit"); 91562306a36Sopenharmony_ci return -EINVAL; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci err = devlink->ops->trap_policer_set(devlink, policer_item->policer, 91962306a36Sopenharmony_ci rate, burst, info->extack); 92062306a36Sopenharmony_ci if (err) 92162306a36Sopenharmony_ci return err; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci policer_item->rate = rate; 92462306a36Sopenharmony_ci policer_item->burst = burst; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ciint devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb, 93062306a36Sopenharmony_ci struct genl_info *info) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 93362306a36Sopenharmony_ci struct netlink_ext_ack *extack = info->extack; 93462306a36Sopenharmony_ci struct devlink *devlink = info->user_ptr[0]; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (list_empty(&devlink->trap_policer_list)) 93762306a36Sopenharmony_ci return -EOPNOTSUPP; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (!devlink->ops->trap_policer_set) 94062306a36Sopenharmony_ci return -EOPNOTSUPP; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci policer_item = devlink_trap_policer_item_get_from_info(devlink, info); 94362306a36Sopenharmony_ci if (!policer_item) { 94462306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Device did not register this trap policer"); 94562306a36Sopenharmony_ci return -ENOENT; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return devlink_trap_policer_set(devlink, policer_item, info); 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci#define DEVLINK_TRAP(_id, _type) \ 95262306a36Sopenharmony_ci { \ 95362306a36Sopenharmony_ci .type = DEVLINK_TRAP_TYPE_##_type, \ 95462306a36Sopenharmony_ci .id = DEVLINK_TRAP_GENERIC_ID_##_id, \ 95562306a36Sopenharmony_ci .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \ 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic const struct devlink_trap devlink_trap_generic[] = { 95962306a36Sopenharmony_ci DEVLINK_TRAP(SMAC_MC, DROP), 96062306a36Sopenharmony_ci DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP), 96162306a36Sopenharmony_ci DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP), 96262306a36Sopenharmony_ci DEVLINK_TRAP(INGRESS_STP_FILTER, DROP), 96362306a36Sopenharmony_ci DEVLINK_TRAP(EMPTY_TX_LIST, DROP), 96462306a36Sopenharmony_ci DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP), 96562306a36Sopenharmony_ci DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP), 96662306a36Sopenharmony_ci DEVLINK_TRAP(TTL_ERROR, EXCEPTION), 96762306a36Sopenharmony_ci DEVLINK_TRAP(TAIL_DROP, DROP), 96862306a36Sopenharmony_ci DEVLINK_TRAP(NON_IP_PACKET, DROP), 96962306a36Sopenharmony_ci DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP), 97062306a36Sopenharmony_ci DEVLINK_TRAP(DIP_LB, DROP), 97162306a36Sopenharmony_ci DEVLINK_TRAP(SIP_MC, DROP), 97262306a36Sopenharmony_ci DEVLINK_TRAP(SIP_LB, DROP), 97362306a36Sopenharmony_ci DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP), 97462306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_SIP_BC, DROP), 97562306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP), 97662306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP), 97762306a36Sopenharmony_ci DEVLINK_TRAP(MTU_ERROR, EXCEPTION), 97862306a36Sopenharmony_ci DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION), 97962306a36Sopenharmony_ci DEVLINK_TRAP(RPF, EXCEPTION), 98062306a36Sopenharmony_ci DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION), 98162306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION), 98262306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION), 98362306a36Sopenharmony_ci DEVLINK_TRAP(NON_ROUTABLE, DROP), 98462306a36Sopenharmony_ci DEVLINK_TRAP(DECAP_ERROR, EXCEPTION), 98562306a36Sopenharmony_ci DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP), 98662306a36Sopenharmony_ci DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP), 98762306a36Sopenharmony_ci DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP), 98862306a36Sopenharmony_ci DEVLINK_TRAP(STP, CONTROL), 98962306a36Sopenharmony_ci DEVLINK_TRAP(LACP, CONTROL), 99062306a36Sopenharmony_ci DEVLINK_TRAP(LLDP, CONTROL), 99162306a36Sopenharmony_ci DEVLINK_TRAP(IGMP_QUERY, CONTROL), 99262306a36Sopenharmony_ci DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL), 99362306a36Sopenharmony_ci DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL), 99462306a36Sopenharmony_ci DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL), 99562306a36Sopenharmony_ci DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL), 99662306a36Sopenharmony_ci DEVLINK_TRAP(MLD_QUERY, CONTROL), 99762306a36Sopenharmony_ci DEVLINK_TRAP(MLD_V1_REPORT, CONTROL), 99862306a36Sopenharmony_ci DEVLINK_TRAP(MLD_V2_REPORT, CONTROL), 99962306a36Sopenharmony_ci DEVLINK_TRAP(MLD_V1_DONE, CONTROL), 100062306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_DHCP, CONTROL), 100162306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_DHCP, CONTROL), 100262306a36Sopenharmony_ci DEVLINK_TRAP(ARP_REQUEST, CONTROL), 100362306a36Sopenharmony_ci DEVLINK_TRAP(ARP_RESPONSE, CONTROL), 100462306a36Sopenharmony_ci DEVLINK_TRAP(ARP_OVERLAY, CONTROL), 100562306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL), 100662306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL), 100762306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_BFD, CONTROL), 100862306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_BFD, CONTROL), 100962306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_OSPF, CONTROL), 101062306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_OSPF, CONTROL), 101162306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_BGP, CONTROL), 101262306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_BGP, CONTROL), 101362306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_VRRP, CONTROL), 101462306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_VRRP, CONTROL), 101562306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_PIM, CONTROL), 101662306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_PIM, CONTROL), 101762306a36Sopenharmony_ci DEVLINK_TRAP(UC_LB, CONTROL), 101862306a36Sopenharmony_ci DEVLINK_TRAP(LOCAL_ROUTE, CONTROL), 101962306a36Sopenharmony_ci DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL), 102062306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL), 102162306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL), 102262306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL), 102362306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL), 102462306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL), 102562306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_REDIRECT, CONTROL), 102662306a36Sopenharmony_ci DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL), 102762306a36Sopenharmony_ci DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL), 102862306a36Sopenharmony_ci DEVLINK_TRAP(PTP_EVENT, CONTROL), 102962306a36Sopenharmony_ci DEVLINK_TRAP(PTP_GENERAL, CONTROL), 103062306a36Sopenharmony_ci DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL), 103162306a36Sopenharmony_ci DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL), 103262306a36Sopenharmony_ci DEVLINK_TRAP(EARLY_DROP, DROP), 103362306a36Sopenharmony_ci DEVLINK_TRAP(VXLAN_PARSING, DROP), 103462306a36Sopenharmony_ci DEVLINK_TRAP(LLC_SNAP_PARSING, DROP), 103562306a36Sopenharmony_ci DEVLINK_TRAP(VLAN_PARSING, DROP), 103662306a36Sopenharmony_ci DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP), 103762306a36Sopenharmony_ci DEVLINK_TRAP(MPLS_PARSING, DROP), 103862306a36Sopenharmony_ci DEVLINK_TRAP(ARP_PARSING, DROP), 103962306a36Sopenharmony_ci DEVLINK_TRAP(IP_1_PARSING, DROP), 104062306a36Sopenharmony_ci DEVLINK_TRAP(IP_N_PARSING, DROP), 104162306a36Sopenharmony_ci DEVLINK_TRAP(GRE_PARSING, DROP), 104262306a36Sopenharmony_ci DEVLINK_TRAP(UDP_PARSING, DROP), 104362306a36Sopenharmony_ci DEVLINK_TRAP(TCP_PARSING, DROP), 104462306a36Sopenharmony_ci DEVLINK_TRAP(IPSEC_PARSING, DROP), 104562306a36Sopenharmony_ci DEVLINK_TRAP(SCTP_PARSING, DROP), 104662306a36Sopenharmony_ci DEVLINK_TRAP(DCCP_PARSING, DROP), 104762306a36Sopenharmony_ci DEVLINK_TRAP(GTP_PARSING, DROP), 104862306a36Sopenharmony_ci DEVLINK_TRAP(ESP_PARSING, DROP), 104962306a36Sopenharmony_ci DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP), 105062306a36Sopenharmony_ci DEVLINK_TRAP(DMAC_FILTER, DROP), 105162306a36Sopenharmony_ci DEVLINK_TRAP(EAPOL, CONTROL), 105262306a36Sopenharmony_ci DEVLINK_TRAP(LOCKED_PORT, DROP), 105362306a36Sopenharmony_ci}; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci#define DEVLINK_TRAP_GROUP(_id) \ 105662306a36Sopenharmony_ci { \ 105762306a36Sopenharmony_ci .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \ 105862306a36Sopenharmony_ci .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \ 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic const struct devlink_trap_group devlink_trap_group_generic[] = { 106262306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(L2_DROPS), 106362306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(L3_DROPS), 106462306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(L3_EXCEPTIONS), 106562306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(BUFFER_DROPS), 106662306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(TUNNEL_DROPS), 106762306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_DROPS), 106862306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(STP), 106962306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(LACP), 107062306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(LLDP), 107162306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(MC_SNOOPING), 107262306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(DHCP), 107362306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY), 107462306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(BFD), 107562306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(OSPF), 107662306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(BGP), 107762306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(VRRP), 107862306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(PIM), 107962306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(UC_LB), 108062306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(LOCAL_DELIVERY), 108162306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY), 108262306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(IPV6), 108362306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(PTP_EVENT), 108462306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(PTP_GENERAL), 108562306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_SAMPLE), 108662306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(ACL_TRAP), 108762306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS), 108862306a36Sopenharmony_ci DEVLINK_TRAP_GROUP(EAPOL), 108962306a36Sopenharmony_ci}; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int devlink_trap_generic_verify(const struct devlink_trap *trap) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX) 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (strcmp(trap->name, devlink_trap_generic[trap->id].name)) 109762306a36Sopenharmony_ci return -EINVAL; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (trap->type != devlink_trap_generic[trap->id].type) 110062306a36Sopenharmony_ci return -EINVAL; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int devlink_trap_driver_verify(const struct devlink_trap *trap) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci int i; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX) 111062306a36Sopenharmony_ci return -EINVAL; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) { 111362306a36Sopenharmony_ci if (!strcmp(trap->name, devlink_trap_generic[i].name)) 111462306a36Sopenharmony_ci return -EEXIST; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return 0; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int devlink_trap_verify(const struct devlink_trap *trap) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci if (!trap || !trap->name) 112362306a36Sopenharmony_ci return -EINVAL; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (trap->generic) 112662306a36Sopenharmony_ci return devlink_trap_generic_verify(trap); 112762306a36Sopenharmony_ci else 112862306a36Sopenharmony_ci return devlink_trap_driver_verify(trap); 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cistatic int 113262306a36Sopenharmony_cidevlink_trap_group_generic_verify(const struct devlink_trap_group *group) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX) 113562306a36Sopenharmony_ci return -EINVAL; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (strcmp(group->name, devlink_trap_group_generic[group->id].name)) 113862306a36Sopenharmony_ci return -EINVAL; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci return 0; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic int 114462306a36Sopenharmony_cidevlink_trap_group_driver_verify(const struct devlink_trap_group *group) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci int i; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX) 114962306a36Sopenharmony_ci return -EINVAL; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) { 115262306a36Sopenharmony_ci if (!strcmp(group->name, devlink_trap_group_generic[i].name)) 115362306a36Sopenharmony_ci return -EEXIST; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int devlink_trap_group_verify(const struct devlink_trap_group *group) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci if (group->generic) 116262306a36Sopenharmony_ci return devlink_trap_group_generic_verify(group); 116362306a36Sopenharmony_ci else 116462306a36Sopenharmony_ci return devlink_trap_group_driver_verify(group); 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic void 116862306a36Sopenharmony_cidevlink_trap_group_notify(struct devlink *devlink, 116962306a36Sopenharmony_ci const struct devlink_trap_group_item *group_item, 117062306a36Sopenharmony_ci enum devlink_command cmd) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct sk_buff *msg; 117362306a36Sopenharmony_ci int err; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW && 117662306a36Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_GROUP_DEL); 117762306a36Sopenharmony_ci if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) 117862306a36Sopenharmony_ci return; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 118162306a36Sopenharmony_ci if (!msg) 118262306a36Sopenharmony_ci return; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0, 118562306a36Sopenharmony_ci 0); 118662306a36Sopenharmony_ci if (err) { 118762306a36Sopenharmony_ci nlmsg_free(msg); 118862306a36Sopenharmony_ci return; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 119262306a36Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_civoid devlink_trap_groups_notify_register(struct devlink *devlink) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci list_for_each_entry(group_item, &devlink->trap_group_list, list) 120062306a36Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 120162306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_civoid devlink_trap_groups_notify_unregister(struct devlink *devlink) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci list_for_each_entry_reverse(group_item, &devlink->trap_group_list, list) 120962306a36Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 121062306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_DEL); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic int 121462306a36Sopenharmony_cidevlink_trap_item_group_link(struct devlink *devlink, 121562306a36Sopenharmony_ci struct devlink_trap_item *trap_item) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci u16 group_id = trap_item->trap->init_group_id; 121862306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id); 122162306a36Sopenharmony_ci if (WARN_ON_ONCE(!group_item)) 122262306a36Sopenharmony_ci return -EINVAL; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci trap_item->group_item = group_item; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci return 0; 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_cistatic void devlink_trap_notify(struct devlink *devlink, 123062306a36Sopenharmony_ci const struct devlink_trap_item *trap_item, 123162306a36Sopenharmony_ci enum devlink_command cmd) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct sk_buff *msg; 123462306a36Sopenharmony_ci int err; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW && 123762306a36Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_DEL); 123862306a36Sopenharmony_ci if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) 123962306a36Sopenharmony_ci return; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 124262306a36Sopenharmony_ci if (!msg) 124362306a36Sopenharmony_ci return; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0); 124662306a36Sopenharmony_ci if (err) { 124762306a36Sopenharmony_ci nlmsg_free(msg); 124862306a36Sopenharmony_ci return; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 125262306a36Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_civoid devlink_traps_notify_register(struct devlink *devlink) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci list_for_each_entry(trap_item, &devlink->trap_list, list) 126062306a36Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW); 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_civoid devlink_traps_notify_unregister(struct devlink *devlink) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci list_for_each_entry_reverse(trap_item, &devlink->trap_list, list) 126862306a36Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL); 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic int 127262306a36Sopenharmony_cidevlink_trap_register(struct devlink *devlink, 127362306a36Sopenharmony_ci const struct devlink_trap *trap, void *priv) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 127662306a36Sopenharmony_ci int err; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (devlink_trap_item_lookup(devlink, trap->name)) 127962306a36Sopenharmony_ci return -EEXIST; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL); 128262306a36Sopenharmony_ci if (!trap_item) 128362306a36Sopenharmony_ci return -ENOMEM; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats); 128662306a36Sopenharmony_ci if (!trap_item->stats) { 128762306a36Sopenharmony_ci err = -ENOMEM; 128862306a36Sopenharmony_ci goto err_stats_alloc; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci trap_item->trap = trap; 129262306a36Sopenharmony_ci trap_item->action = trap->init_action; 129362306a36Sopenharmony_ci trap_item->priv = priv; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci err = devlink_trap_item_group_link(devlink, trap_item); 129662306a36Sopenharmony_ci if (err) 129762306a36Sopenharmony_ci goto err_group_link; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci err = devlink->ops->trap_init(devlink, trap, trap_item); 130062306a36Sopenharmony_ci if (err) 130162306a36Sopenharmony_ci goto err_trap_init; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci list_add_tail(&trap_item->list, &devlink->trap_list); 130462306a36Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cierr_trap_init: 130962306a36Sopenharmony_cierr_group_link: 131062306a36Sopenharmony_ci free_percpu(trap_item->stats); 131162306a36Sopenharmony_cierr_stats_alloc: 131262306a36Sopenharmony_ci kfree(trap_item); 131362306a36Sopenharmony_ci return err; 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void devlink_trap_unregister(struct devlink *devlink, 131762306a36Sopenharmony_ci const struct devlink_trap *trap) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci trap_item = devlink_trap_item_lookup(devlink, trap->name); 132262306a36Sopenharmony_ci if (WARN_ON_ONCE(!trap_item)) 132362306a36Sopenharmony_ci return; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL); 132662306a36Sopenharmony_ci list_del(&trap_item->list); 132762306a36Sopenharmony_ci if (devlink->ops->trap_fini) 132862306a36Sopenharmony_ci devlink->ops->trap_fini(devlink, trap, trap_item); 132962306a36Sopenharmony_ci free_percpu(trap_item->stats); 133062306a36Sopenharmony_ci kfree(trap_item); 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic void devlink_trap_disable(struct devlink *devlink, 133462306a36Sopenharmony_ci const struct devlink_trap *trap) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci struct devlink_trap_item *trap_item; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci trap_item = devlink_trap_item_lookup(devlink, trap->name); 133962306a36Sopenharmony_ci if (WARN_ON_ONCE(!trap_item)) 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP, 134362306a36Sopenharmony_ci NULL); 134462306a36Sopenharmony_ci trap_item->action = DEVLINK_TRAP_ACTION_DROP; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci/** 134862306a36Sopenharmony_ci * devl_traps_register - Register packet traps with devlink. 134962306a36Sopenharmony_ci * @devlink: devlink. 135062306a36Sopenharmony_ci * @traps: Packet traps. 135162306a36Sopenharmony_ci * @traps_count: Count of provided packet traps. 135262306a36Sopenharmony_ci * @priv: Driver private information. 135362306a36Sopenharmony_ci * 135462306a36Sopenharmony_ci * Return: Non-zero value on failure. 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_ciint devl_traps_register(struct devlink *devlink, 135762306a36Sopenharmony_ci const struct devlink_trap *traps, 135862306a36Sopenharmony_ci size_t traps_count, void *priv) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci int i, err; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (!devlink->ops->trap_init || !devlink->ops->trap_action_set) 136362306a36Sopenharmony_ci return -EINVAL; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci devl_assert_locked(devlink); 136662306a36Sopenharmony_ci for (i = 0; i < traps_count; i++) { 136762306a36Sopenharmony_ci const struct devlink_trap *trap = &traps[i]; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci err = devlink_trap_verify(trap); 137062306a36Sopenharmony_ci if (err) 137162306a36Sopenharmony_ci goto err_trap_verify; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci err = devlink_trap_register(devlink, trap, priv); 137462306a36Sopenharmony_ci if (err) 137562306a36Sopenharmony_ci goto err_trap_register; 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cierr_trap_register: 138162306a36Sopenharmony_cierr_trap_verify: 138262306a36Sopenharmony_ci for (i--; i >= 0; i--) 138362306a36Sopenharmony_ci devlink_trap_unregister(devlink, &traps[i]); 138462306a36Sopenharmony_ci return err; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_traps_register); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci/** 138962306a36Sopenharmony_ci * devlink_traps_register - Register packet traps with devlink. 139062306a36Sopenharmony_ci * @devlink: devlink. 139162306a36Sopenharmony_ci * @traps: Packet traps. 139262306a36Sopenharmony_ci * @traps_count: Count of provided packet traps. 139362306a36Sopenharmony_ci * @priv: Driver private information. 139462306a36Sopenharmony_ci * 139562306a36Sopenharmony_ci * Context: Takes and release devlink->lock <mutex>. 139662306a36Sopenharmony_ci * 139762306a36Sopenharmony_ci * Return: Non-zero value on failure. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_ciint devlink_traps_register(struct devlink *devlink, 140062306a36Sopenharmony_ci const struct devlink_trap *traps, 140162306a36Sopenharmony_ci size_t traps_count, void *priv) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci int err; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci devl_lock(devlink); 140662306a36Sopenharmony_ci err = devl_traps_register(devlink, traps, traps_count, priv); 140762306a36Sopenharmony_ci devl_unlock(devlink); 140862306a36Sopenharmony_ci return err; 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_register); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci/** 141362306a36Sopenharmony_ci * devl_traps_unregister - Unregister packet traps from devlink. 141462306a36Sopenharmony_ci * @devlink: devlink. 141562306a36Sopenharmony_ci * @traps: Packet traps. 141662306a36Sopenharmony_ci * @traps_count: Count of provided packet traps. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_civoid devl_traps_unregister(struct devlink *devlink, 141962306a36Sopenharmony_ci const struct devlink_trap *traps, 142062306a36Sopenharmony_ci size_t traps_count) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci int i; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci devl_assert_locked(devlink); 142562306a36Sopenharmony_ci /* Make sure we do not have any packets in-flight while unregistering 142662306a36Sopenharmony_ci * traps by disabling all of them and waiting for a grace period. 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_ci for (i = traps_count - 1; i >= 0; i--) 142962306a36Sopenharmony_ci devlink_trap_disable(devlink, &traps[i]); 143062306a36Sopenharmony_ci synchronize_rcu(); 143162306a36Sopenharmony_ci for (i = traps_count - 1; i >= 0; i--) 143262306a36Sopenharmony_ci devlink_trap_unregister(devlink, &traps[i]); 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_traps_unregister); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci/** 143762306a36Sopenharmony_ci * devlink_traps_unregister - Unregister packet traps from devlink. 143862306a36Sopenharmony_ci * @devlink: devlink. 143962306a36Sopenharmony_ci * @traps: Packet traps. 144062306a36Sopenharmony_ci * @traps_count: Count of provided packet traps. 144162306a36Sopenharmony_ci * 144262306a36Sopenharmony_ci * Context: Takes and release devlink->lock <mutex>. 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_civoid devlink_traps_unregister(struct devlink *devlink, 144562306a36Sopenharmony_ci const struct devlink_trap *traps, 144662306a36Sopenharmony_ci size_t traps_count) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci devl_lock(devlink); 144962306a36Sopenharmony_ci devl_traps_unregister(devlink, traps, traps_count); 145062306a36Sopenharmony_ci devl_unlock(devlink); 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_unregister); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_cistatic void 145562306a36Sopenharmony_cidevlink_trap_stats_update(struct devlink_stats __percpu *trap_stats, 145662306a36Sopenharmony_ci size_t skb_len) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci struct devlink_stats *stats; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci stats = this_cpu_ptr(trap_stats); 146162306a36Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 146262306a36Sopenharmony_ci u64_stats_add(&stats->rx_bytes, skb_len); 146362306a36Sopenharmony_ci u64_stats_inc(&stats->rx_packets); 146462306a36Sopenharmony_ci u64_stats_update_end(&stats->syncp); 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic void 146862306a36Sopenharmony_cidevlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata, 146962306a36Sopenharmony_ci const struct devlink_trap_item *trap_item, 147062306a36Sopenharmony_ci struct devlink_port *in_devlink_port, 147162306a36Sopenharmony_ci const struct flow_action_cookie *fa_cookie) 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci metadata->trap_name = trap_item->trap->name; 147462306a36Sopenharmony_ci metadata->trap_group_name = trap_item->group_item->group->name; 147562306a36Sopenharmony_ci metadata->fa_cookie = fa_cookie; 147662306a36Sopenharmony_ci metadata->trap_type = trap_item->trap->type; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci spin_lock(&in_devlink_port->type_lock); 147962306a36Sopenharmony_ci if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH) 148062306a36Sopenharmony_ci metadata->input_dev = in_devlink_port->type_eth.netdev; 148162306a36Sopenharmony_ci spin_unlock(&in_devlink_port->type_lock); 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci/** 148562306a36Sopenharmony_ci * devlink_trap_report - Report trapped packet to drop monitor. 148662306a36Sopenharmony_ci * @devlink: devlink. 148762306a36Sopenharmony_ci * @skb: Trapped packet. 148862306a36Sopenharmony_ci * @trap_ctx: Trap context. 148962306a36Sopenharmony_ci * @in_devlink_port: Input devlink port. 149062306a36Sopenharmony_ci * @fa_cookie: Flow action cookie. Could be NULL. 149162306a36Sopenharmony_ci */ 149262306a36Sopenharmony_civoid devlink_trap_report(struct devlink *devlink, struct sk_buff *skb, 149362306a36Sopenharmony_ci void *trap_ctx, struct devlink_port *in_devlink_port, 149462306a36Sopenharmony_ci const struct flow_action_cookie *fa_cookie) 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci struct devlink_trap_item *trap_item = trap_ctx; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci devlink_trap_stats_update(trap_item->stats, skb->len); 150062306a36Sopenharmony_ci devlink_trap_stats_update(trap_item->group_item->stats, skb->len); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci if (tracepoint_enabled(devlink_trap_report)) { 150362306a36Sopenharmony_ci struct devlink_trap_metadata metadata = {}; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci devlink_trap_report_metadata_set(&metadata, trap_item, 150662306a36Sopenharmony_ci in_devlink_port, fa_cookie); 150762306a36Sopenharmony_ci trace_devlink_trap_report(devlink, skb, &metadata); 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_report); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci/** 151362306a36Sopenharmony_ci * devlink_trap_ctx_priv - Trap context to driver private information. 151462306a36Sopenharmony_ci * @trap_ctx: Trap context. 151562306a36Sopenharmony_ci * 151662306a36Sopenharmony_ci * Return: Driver private information passed during registration. 151762306a36Sopenharmony_ci */ 151862306a36Sopenharmony_civoid *devlink_trap_ctx_priv(void *trap_ctx) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct devlink_trap_item *trap_item = trap_ctx; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci return trap_item->priv; 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_ctx_priv); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic int 152762306a36Sopenharmony_cidevlink_trap_group_item_policer_link(struct devlink *devlink, 152862306a36Sopenharmony_ci struct devlink_trap_group_item *group_item) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci u32 policer_id = group_item->group->init_policer_id; 153162306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (policer_id == 0) 153462306a36Sopenharmony_ci return 0; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, policer_id); 153762306a36Sopenharmony_ci if (WARN_ON_ONCE(!policer_item)) 153862306a36Sopenharmony_ci return -EINVAL; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci group_item->policer_item = policer_item; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci return 0; 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic int 154662306a36Sopenharmony_cidevlink_trap_group_register(struct devlink *devlink, 154762306a36Sopenharmony_ci const struct devlink_trap_group *group) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 155062306a36Sopenharmony_ci int err; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (devlink_trap_group_item_lookup(devlink, group->name)) 155362306a36Sopenharmony_ci return -EEXIST; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci group_item = kzalloc(sizeof(*group_item), GFP_KERNEL); 155662306a36Sopenharmony_ci if (!group_item) 155762306a36Sopenharmony_ci return -ENOMEM; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats); 156062306a36Sopenharmony_ci if (!group_item->stats) { 156162306a36Sopenharmony_ci err = -ENOMEM; 156262306a36Sopenharmony_ci goto err_stats_alloc; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci group_item->group = group; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci err = devlink_trap_group_item_policer_link(devlink, group_item); 156862306a36Sopenharmony_ci if (err) 156962306a36Sopenharmony_ci goto err_policer_link; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (devlink->ops->trap_group_init) { 157262306a36Sopenharmony_ci err = devlink->ops->trap_group_init(devlink, group); 157362306a36Sopenharmony_ci if (err) 157462306a36Sopenharmony_ci goto err_group_init; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci list_add_tail(&group_item->list, &devlink->trap_group_list); 157862306a36Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 157962306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_NEW); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci return 0; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cierr_group_init: 158462306a36Sopenharmony_cierr_policer_link: 158562306a36Sopenharmony_ci free_percpu(group_item->stats); 158662306a36Sopenharmony_cierr_stats_alloc: 158762306a36Sopenharmony_ci kfree(group_item); 158862306a36Sopenharmony_ci return err; 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic void 159262306a36Sopenharmony_cidevlink_trap_group_unregister(struct devlink *devlink, 159362306a36Sopenharmony_ci const struct devlink_trap_group *group) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci struct devlink_trap_group_item *group_item; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci group_item = devlink_trap_group_item_lookup(devlink, group->name); 159862306a36Sopenharmony_ci if (WARN_ON_ONCE(!group_item)) 159962306a36Sopenharmony_ci return; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci devlink_trap_group_notify(devlink, group_item, 160262306a36Sopenharmony_ci DEVLINK_CMD_TRAP_GROUP_DEL); 160362306a36Sopenharmony_ci list_del(&group_item->list); 160462306a36Sopenharmony_ci free_percpu(group_item->stats); 160562306a36Sopenharmony_ci kfree(group_item); 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci/** 160962306a36Sopenharmony_ci * devl_trap_groups_register - Register packet trap groups with devlink. 161062306a36Sopenharmony_ci * @devlink: devlink. 161162306a36Sopenharmony_ci * @groups: Packet trap groups. 161262306a36Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 161362306a36Sopenharmony_ci * 161462306a36Sopenharmony_ci * Return: Non-zero value on failure. 161562306a36Sopenharmony_ci */ 161662306a36Sopenharmony_ciint devl_trap_groups_register(struct devlink *devlink, 161762306a36Sopenharmony_ci const struct devlink_trap_group *groups, 161862306a36Sopenharmony_ci size_t groups_count) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci int i, err; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci devl_assert_locked(devlink); 162362306a36Sopenharmony_ci for (i = 0; i < groups_count; i++) { 162462306a36Sopenharmony_ci const struct devlink_trap_group *group = &groups[i]; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci err = devlink_trap_group_verify(group); 162762306a36Sopenharmony_ci if (err) 162862306a36Sopenharmony_ci goto err_trap_group_verify; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci err = devlink_trap_group_register(devlink, group); 163162306a36Sopenharmony_ci if (err) 163262306a36Sopenharmony_ci goto err_trap_group_register; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci return 0; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cierr_trap_group_register: 163862306a36Sopenharmony_cierr_trap_group_verify: 163962306a36Sopenharmony_ci for (i--; i >= 0; i--) 164062306a36Sopenharmony_ci devlink_trap_group_unregister(devlink, &groups[i]); 164162306a36Sopenharmony_ci return err; 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_trap_groups_register); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci/** 164662306a36Sopenharmony_ci * devlink_trap_groups_register - Register packet trap groups with devlink. 164762306a36Sopenharmony_ci * @devlink: devlink. 164862306a36Sopenharmony_ci * @groups: Packet trap groups. 164962306a36Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * Context: Takes and release devlink->lock <mutex>. 165262306a36Sopenharmony_ci * 165362306a36Sopenharmony_ci * Return: Non-zero value on failure. 165462306a36Sopenharmony_ci */ 165562306a36Sopenharmony_ciint devlink_trap_groups_register(struct devlink *devlink, 165662306a36Sopenharmony_ci const struct devlink_trap_group *groups, 165762306a36Sopenharmony_ci size_t groups_count) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci int err; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci devl_lock(devlink); 166262306a36Sopenharmony_ci err = devl_trap_groups_register(devlink, groups, groups_count); 166362306a36Sopenharmony_ci devl_unlock(devlink); 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_register); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci/** 166962306a36Sopenharmony_ci * devl_trap_groups_unregister - Unregister packet trap groups from devlink. 167062306a36Sopenharmony_ci * @devlink: devlink. 167162306a36Sopenharmony_ci * @groups: Packet trap groups. 167262306a36Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 167362306a36Sopenharmony_ci */ 167462306a36Sopenharmony_civoid devl_trap_groups_unregister(struct devlink *devlink, 167562306a36Sopenharmony_ci const struct devlink_trap_group *groups, 167662306a36Sopenharmony_ci size_t groups_count) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci int i; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci devl_assert_locked(devlink); 168162306a36Sopenharmony_ci for (i = groups_count - 1; i >= 0; i--) 168262306a36Sopenharmony_ci devlink_trap_group_unregister(devlink, &groups[i]); 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_trap_groups_unregister); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci/** 168762306a36Sopenharmony_ci * devlink_trap_groups_unregister - Unregister packet trap groups from devlink. 168862306a36Sopenharmony_ci * @devlink: devlink. 168962306a36Sopenharmony_ci * @groups: Packet trap groups. 169062306a36Sopenharmony_ci * @groups_count: Count of provided packet trap groups. 169162306a36Sopenharmony_ci * 169262306a36Sopenharmony_ci * Context: Takes and release devlink->lock <mutex>. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_civoid devlink_trap_groups_unregister(struct devlink *devlink, 169562306a36Sopenharmony_ci const struct devlink_trap_group *groups, 169662306a36Sopenharmony_ci size_t groups_count) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci devl_lock(devlink); 169962306a36Sopenharmony_ci devl_trap_groups_unregister(devlink, groups, groups_count); 170062306a36Sopenharmony_ci devl_unlock(devlink); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_unregister); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic void 170562306a36Sopenharmony_cidevlink_trap_policer_notify(struct devlink *devlink, 170662306a36Sopenharmony_ci const struct devlink_trap_policer_item *policer_item, 170762306a36Sopenharmony_ci enum devlink_command cmd) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci struct sk_buff *msg; 171062306a36Sopenharmony_ci int err; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW && 171362306a36Sopenharmony_ci cmd != DEVLINK_CMD_TRAP_POLICER_DEL); 171462306a36Sopenharmony_ci if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) 171562306a36Sopenharmony_ci return; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 171862306a36Sopenharmony_ci if (!msg) 171962306a36Sopenharmony_ci return; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0, 172262306a36Sopenharmony_ci 0, 0); 172362306a36Sopenharmony_ci if (err) { 172462306a36Sopenharmony_ci nlmsg_free(msg); 172562306a36Sopenharmony_ci return; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 172962306a36Sopenharmony_ci msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_civoid devlink_trap_policers_notify_register(struct devlink *devlink) 173362306a36Sopenharmony_ci{ 173462306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci list_for_each_entry(policer_item, &devlink->trap_policer_list, list) 173762306a36Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 173862306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW); 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_civoid devlink_trap_policers_notify_unregister(struct devlink *devlink) 174262306a36Sopenharmony_ci{ 174362306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci list_for_each_entry_reverse(policer_item, &devlink->trap_policer_list, 174662306a36Sopenharmony_ci list) 174762306a36Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 174862306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_DEL); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cistatic int 175262306a36Sopenharmony_cidevlink_trap_policer_register(struct devlink *devlink, 175362306a36Sopenharmony_ci const struct devlink_trap_policer *policer) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 175662306a36Sopenharmony_ci int err; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (devlink_trap_policer_item_lookup(devlink, policer->id)) 175962306a36Sopenharmony_ci return -EEXIST; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL); 176262306a36Sopenharmony_ci if (!policer_item) 176362306a36Sopenharmony_ci return -ENOMEM; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci policer_item->policer = policer; 176662306a36Sopenharmony_ci policer_item->rate = policer->init_rate; 176762306a36Sopenharmony_ci policer_item->burst = policer->init_burst; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci if (devlink->ops->trap_policer_init) { 177062306a36Sopenharmony_ci err = devlink->ops->trap_policer_init(devlink, policer); 177162306a36Sopenharmony_ci if (err) 177262306a36Sopenharmony_ci goto err_policer_init; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci list_add_tail(&policer_item->list, &devlink->trap_policer_list); 177662306a36Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 177762306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_NEW); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci return 0; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cierr_policer_init: 178262306a36Sopenharmony_ci kfree(policer_item); 178362306a36Sopenharmony_ci return err; 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_cistatic void 178762306a36Sopenharmony_cidevlink_trap_policer_unregister(struct devlink *devlink, 178862306a36Sopenharmony_ci const struct devlink_trap_policer *policer) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci struct devlink_trap_policer_item *policer_item; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci policer_item = devlink_trap_policer_item_lookup(devlink, policer->id); 179362306a36Sopenharmony_ci if (WARN_ON_ONCE(!policer_item)) 179462306a36Sopenharmony_ci return; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci devlink_trap_policer_notify(devlink, policer_item, 179762306a36Sopenharmony_ci DEVLINK_CMD_TRAP_POLICER_DEL); 179862306a36Sopenharmony_ci list_del(&policer_item->list); 179962306a36Sopenharmony_ci if (devlink->ops->trap_policer_fini) 180062306a36Sopenharmony_ci devlink->ops->trap_policer_fini(devlink, policer); 180162306a36Sopenharmony_ci kfree(policer_item); 180262306a36Sopenharmony_ci} 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci/** 180562306a36Sopenharmony_ci * devl_trap_policers_register - Register packet trap policers with devlink. 180662306a36Sopenharmony_ci * @devlink: devlink. 180762306a36Sopenharmony_ci * @policers: Packet trap policers. 180862306a36Sopenharmony_ci * @policers_count: Count of provided packet trap policers. 180962306a36Sopenharmony_ci * 181062306a36Sopenharmony_ci * Return: Non-zero value on failure. 181162306a36Sopenharmony_ci */ 181262306a36Sopenharmony_ciint 181362306a36Sopenharmony_cidevl_trap_policers_register(struct devlink *devlink, 181462306a36Sopenharmony_ci const struct devlink_trap_policer *policers, 181562306a36Sopenharmony_ci size_t policers_count) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci int i, err; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci devl_assert_locked(devlink); 182062306a36Sopenharmony_ci for (i = 0; i < policers_count; i++) { 182162306a36Sopenharmony_ci const struct devlink_trap_policer *policer = &policers[i]; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (WARN_ON(policer->id == 0 || 182462306a36Sopenharmony_ci policer->max_rate < policer->min_rate || 182562306a36Sopenharmony_ci policer->max_burst < policer->min_burst)) { 182662306a36Sopenharmony_ci err = -EINVAL; 182762306a36Sopenharmony_ci goto err_trap_policer_verify; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci err = devlink_trap_policer_register(devlink, policer); 183162306a36Sopenharmony_ci if (err) 183262306a36Sopenharmony_ci goto err_trap_policer_register; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci return 0; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_cierr_trap_policer_register: 183762306a36Sopenharmony_cierr_trap_policer_verify: 183862306a36Sopenharmony_ci for (i--; i >= 0; i--) 183962306a36Sopenharmony_ci devlink_trap_policer_unregister(devlink, &policers[i]); 184062306a36Sopenharmony_ci return err; 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_trap_policers_register); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci/** 184562306a36Sopenharmony_ci * devl_trap_policers_unregister - Unregister packet trap policers from devlink. 184662306a36Sopenharmony_ci * @devlink: devlink. 184762306a36Sopenharmony_ci * @policers: Packet trap policers. 184862306a36Sopenharmony_ci * @policers_count: Count of provided packet trap policers. 184962306a36Sopenharmony_ci */ 185062306a36Sopenharmony_civoid 185162306a36Sopenharmony_cidevl_trap_policers_unregister(struct devlink *devlink, 185262306a36Sopenharmony_ci const struct devlink_trap_policer *policers, 185362306a36Sopenharmony_ci size_t policers_count) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci int i; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci devl_assert_locked(devlink); 185862306a36Sopenharmony_ci for (i = policers_count - 1; i >= 0; i--) 185962306a36Sopenharmony_ci devlink_trap_policer_unregister(devlink, &policers[i]); 186062306a36Sopenharmony_ci} 186162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devl_trap_policers_unregister); 1862