xref: /linux-6.15/net/devlink/trap.c (revision a788acf1)
14bbdec80SJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
24bbdec80SJiri Pirko /*
34bbdec80SJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
44bbdec80SJiri Pirko  * Copyright (c) 2016 Jiri Pirko <[email protected]>
54bbdec80SJiri Pirko  */
64bbdec80SJiri Pirko 
74bbdec80SJiri Pirko #include <trace/events/devlink.h>
84bbdec80SJiri Pirko 
94bbdec80SJiri Pirko #include "devl_internal.h"
104bbdec80SJiri Pirko 
114bbdec80SJiri Pirko struct devlink_stats {
124bbdec80SJiri Pirko 	u64_stats_t rx_bytes;
134bbdec80SJiri Pirko 	u64_stats_t rx_packets;
144bbdec80SJiri Pirko 	struct u64_stats_sync syncp;
154bbdec80SJiri Pirko };
164bbdec80SJiri Pirko 
174bbdec80SJiri Pirko /**
184bbdec80SJiri Pirko  * struct devlink_trap_policer_item - Packet trap policer attributes.
194bbdec80SJiri Pirko  * @policer: Immutable packet trap policer attributes.
204bbdec80SJiri Pirko  * @rate: Rate in packets / sec.
214bbdec80SJiri Pirko  * @burst: Burst size in packets.
224bbdec80SJiri Pirko  * @list: trap_policer_list member.
234bbdec80SJiri Pirko  *
244bbdec80SJiri Pirko  * Describes packet trap policer attributes. Created by devlink during trap
254bbdec80SJiri Pirko  * policer registration.
264bbdec80SJiri Pirko  */
274bbdec80SJiri Pirko struct devlink_trap_policer_item {
284bbdec80SJiri Pirko 	const struct devlink_trap_policer *policer;
294bbdec80SJiri Pirko 	u64 rate;
304bbdec80SJiri Pirko 	u64 burst;
314bbdec80SJiri Pirko 	struct list_head list;
324bbdec80SJiri Pirko };
334bbdec80SJiri Pirko 
344bbdec80SJiri Pirko /**
354bbdec80SJiri Pirko  * struct devlink_trap_group_item - Packet trap group attributes.
364bbdec80SJiri Pirko  * @group: Immutable packet trap group attributes.
374bbdec80SJiri Pirko  * @policer_item: Associated policer item. Can be NULL.
384bbdec80SJiri Pirko  * @list: trap_group_list member.
394bbdec80SJiri Pirko  * @stats: Trap group statistics.
404bbdec80SJiri Pirko  *
414bbdec80SJiri Pirko  * Describes packet trap group attributes. Created by devlink during trap
424bbdec80SJiri Pirko  * group registration.
434bbdec80SJiri Pirko  */
444bbdec80SJiri Pirko struct devlink_trap_group_item {
454bbdec80SJiri Pirko 	const struct devlink_trap_group *group;
464bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
474bbdec80SJiri Pirko 	struct list_head list;
484bbdec80SJiri Pirko 	struct devlink_stats __percpu *stats;
494bbdec80SJiri Pirko };
504bbdec80SJiri Pirko 
514bbdec80SJiri Pirko /**
524bbdec80SJiri Pirko  * struct devlink_trap_item - Packet trap attributes.
534bbdec80SJiri Pirko  * @trap: Immutable packet trap attributes.
544bbdec80SJiri Pirko  * @group_item: Associated group item.
554bbdec80SJiri Pirko  * @list: trap_list member.
564bbdec80SJiri Pirko  * @action: Trap action.
574bbdec80SJiri Pirko  * @stats: Trap statistics.
584bbdec80SJiri Pirko  * @priv: Driver private information.
594bbdec80SJiri Pirko  *
604bbdec80SJiri Pirko  * Describes both mutable and immutable packet trap attributes. Created by
614bbdec80SJiri Pirko  * devlink during trap registration and used for all trap related operations.
624bbdec80SJiri Pirko  */
634bbdec80SJiri Pirko struct devlink_trap_item {
644bbdec80SJiri Pirko 	const struct devlink_trap *trap;
654bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
664bbdec80SJiri Pirko 	struct list_head list;
674bbdec80SJiri Pirko 	enum devlink_trap_action action;
684bbdec80SJiri Pirko 	struct devlink_stats __percpu *stats;
694bbdec80SJiri Pirko 	void *priv;
704bbdec80SJiri Pirko };
714bbdec80SJiri Pirko 
724bbdec80SJiri Pirko static struct devlink_trap_policer_item *
devlink_trap_policer_item_lookup(struct devlink * devlink,u32 id)734bbdec80SJiri Pirko devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
744bbdec80SJiri Pirko {
754bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
764bbdec80SJiri Pirko 
774bbdec80SJiri Pirko 	list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
784bbdec80SJiri Pirko 		if (policer_item->policer->id == id)
794bbdec80SJiri Pirko 			return policer_item;
804bbdec80SJiri Pirko 	}
814bbdec80SJiri Pirko 
824bbdec80SJiri Pirko 	return NULL;
834bbdec80SJiri Pirko }
844bbdec80SJiri Pirko 
854bbdec80SJiri Pirko static struct devlink_trap_item *
devlink_trap_item_lookup(struct devlink * devlink,const char * name)864bbdec80SJiri Pirko devlink_trap_item_lookup(struct devlink *devlink, const char *name)
874bbdec80SJiri Pirko {
884bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
894bbdec80SJiri Pirko 
904bbdec80SJiri Pirko 	list_for_each_entry(trap_item, &devlink->trap_list, list) {
914bbdec80SJiri Pirko 		if (!strcmp(trap_item->trap->name, name))
924bbdec80SJiri Pirko 			return trap_item;
934bbdec80SJiri Pirko 	}
944bbdec80SJiri Pirko 
954bbdec80SJiri Pirko 	return NULL;
964bbdec80SJiri Pirko }
974bbdec80SJiri Pirko 
984bbdec80SJiri Pirko static struct devlink_trap_item *
devlink_trap_item_get_from_info(struct devlink * devlink,struct genl_info * info)994bbdec80SJiri Pirko devlink_trap_item_get_from_info(struct devlink *devlink,
1004bbdec80SJiri Pirko 				struct genl_info *info)
1014bbdec80SJiri Pirko {
1024bbdec80SJiri Pirko 	struct nlattr *attr;
1034bbdec80SJiri Pirko 
1044bbdec80SJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
1054bbdec80SJiri Pirko 		return NULL;
1064bbdec80SJiri Pirko 	attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
1074bbdec80SJiri Pirko 
1084bbdec80SJiri Pirko 	return devlink_trap_item_lookup(devlink, nla_data(attr));
1094bbdec80SJiri Pirko }
1104bbdec80SJiri Pirko 
1114bbdec80SJiri Pirko static int
devlink_trap_action_get_from_info(struct genl_info * info,enum devlink_trap_action * p_trap_action)1124bbdec80SJiri Pirko devlink_trap_action_get_from_info(struct genl_info *info,
1134bbdec80SJiri Pirko 				  enum devlink_trap_action *p_trap_action)
1144bbdec80SJiri Pirko {
1154bbdec80SJiri Pirko 	u8 val;
1164bbdec80SJiri Pirko 
1174bbdec80SJiri Pirko 	val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
1184bbdec80SJiri Pirko 	switch (val) {
1194bbdec80SJiri Pirko 	case DEVLINK_TRAP_ACTION_DROP:
1204bbdec80SJiri Pirko 	case DEVLINK_TRAP_ACTION_TRAP:
1214bbdec80SJiri Pirko 	case DEVLINK_TRAP_ACTION_MIRROR:
1224bbdec80SJiri Pirko 		*p_trap_action = val;
1234bbdec80SJiri Pirko 		break;
1244bbdec80SJiri Pirko 	default:
1254bbdec80SJiri Pirko 		return -EINVAL;
1264bbdec80SJiri Pirko 	}
1274bbdec80SJiri Pirko 
1284bbdec80SJiri Pirko 	return 0;
1294bbdec80SJiri Pirko }
1304bbdec80SJiri Pirko 
devlink_trap_metadata_put(struct sk_buff * msg,const struct devlink_trap * trap)1314bbdec80SJiri Pirko static int devlink_trap_metadata_put(struct sk_buff *msg,
1324bbdec80SJiri Pirko 				     const struct devlink_trap *trap)
1334bbdec80SJiri Pirko {
1344bbdec80SJiri Pirko 	struct nlattr *attr;
1354bbdec80SJiri Pirko 
1364bbdec80SJiri Pirko 	attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
1374bbdec80SJiri Pirko 	if (!attr)
1384bbdec80SJiri Pirko 		return -EMSGSIZE;
1394bbdec80SJiri Pirko 
1404bbdec80SJiri Pirko 	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
1414bbdec80SJiri Pirko 	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
1424bbdec80SJiri Pirko 		goto nla_put_failure;
1434bbdec80SJiri Pirko 	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
1444bbdec80SJiri Pirko 	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
1454bbdec80SJiri Pirko 		goto nla_put_failure;
1464bbdec80SJiri Pirko 
1474bbdec80SJiri Pirko 	nla_nest_end(msg, attr);
1484bbdec80SJiri Pirko 
1494bbdec80SJiri Pirko 	return 0;
1504bbdec80SJiri Pirko 
1514bbdec80SJiri Pirko nla_put_failure:
1524bbdec80SJiri Pirko 	nla_nest_cancel(msg, attr);
1534bbdec80SJiri Pirko 	return -EMSGSIZE;
1544bbdec80SJiri Pirko }
1554bbdec80SJiri Pirko 
devlink_trap_stats_read(struct devlink_stats __percpu * trap_stats,struct devlink_stats * stats)1564bbdec80SJiri Pirko static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
1574bbdec80SJiri Pirko 				    struct devlink_stats *stats)
1584bbdec80SJiri Pirko {
1594bbdec80SJiri Pirko 	int i;
1604bbdec80SJiri Pirko 
1614bbdec80SJiri Pirko 	memset(stats, 0, sizeof(*stats));
1624bbdec80SJiri Pirko 	for_each_possible_cpu(i) {
1634bbdec80SJiri Pirko 		struct devlink_stats *cpu_stats;
1644bbdec80SJiri Pirko 		u64 rx_packets, rx_bytes;
1654bbdec80SJiri Pirko 		unsigned int start;
1664bbdec80SJiri Pirko 
1674bbdec80SJiri Pirko 		cpu_stats = per_cpu_ptr(trap_stats, i);
1684bbdec80SJiri Pirko 		do {
1694bbdec80SJiri Pirko 			start = u64_stats_fetch_begin(&cpu_stats->syncp);
1704bbdec80SJiri Pirko 			rx_packets = u64_stats_read(&cpu_stats->rx_packets);
1714bbdec80SJiri Pirko 			rx_bytes = u64_stats_read(&cpu_stats->rx_bytes);
1724bbdec80SJiri Pirko 		} while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
1734bbdec80SJiri Pirko 
1744bbdec80SJiri Pirko 		u64_stats_add(&stats->rx_packets, rx_packets);
1754bbdec80SJiri Pirko 		u64_stats_add(&stats->rx_bytes, rx_bytes);
1764bbdec80SJiri Pirko 	}
1774bbdec80SJiri Pirko }
1784bbdec80SJiri Pirko 
1794bbdec80SJiri Pirko static int
devlink_trap_group_stats_put(struct sk_buff * msg,struct devlink_stats __percpu * trap_stats)1804bbdec80SJiri Pirko devlink_trap_group_stats_put(struct sk_buff *msg,
1814bbdec80SJiri Pirko 			     struct devlink_stats __percpu *trap_stats)
1824bbdec80SJiri Pirko {
1834bbdec80SJiri Pirko 	struct devlink_stats stats;
1844bbdec80SJiri Pirko 	struct nlattr *attr;
1854bbdec80SJiri Pirko 
1864bbdec80SJiri Pirko 	devlink_trap_stats_read(trap_stats, &stats);
1874bbdec80SJiri Pirko 
1884bbdec80SJiri Pirko 	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
1894bbdec80SJiri Pirko 	if (!attr)
1904bbdec80SJiri Pirko 		return -EMSGSIZE;
1914bbdec80SJiri Pirko 
192*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
193*a788acf1SPrzemek Kitszel 			       u64_stats_read(&stats.rx_packets)))
1944bbdec80SJiri Pirko 		goto nla_put_failure;
1954bbdec80SJiri Pirko 
196*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
197*a788acf1SPrzemek Kitszel 			       u64_stats_read(&stats.rx_bytes)))
1984bbdec80SJiri Pirko 		goto nla_put_failure;
1994bbdec80SJiri Pirko 
2004bbdec80SJiri Pirko 	nla_nest_end(msg, attr);
2014bbdec80SJiri Pirko 
2024bbdec80SJiri Pirko 	return 0;
2034bbdec80SJiri Pirko 
2044bbdec80SJiri Pirko nla_put_failure:
2054bbdec80SJiri Pirko 	nla_nest_cancel(msg, attr);
2064bbdec80SJiri Pirko 	return -EMSGSIZE;
2074bbdec80SJiri Pirko }
2084bbdec80SJiri Pirko 
devlink_trap_stats_put(struct sk_buff * msg,struct devlink * devlink,const struct devlink_trap_item * trap_item)2094bbdec80SJiri Pirko static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
2104bbdec80SJiri Pirko 				  const struct devlink_trap_item *trap_item)
2114bbdec80SJiri Pirko {
2124bbdec80SJiri Pirko 	struct devlink_stats stats;
2134bbdec80SJiri Pirko 	struct nlattr *attr;
2144bbdec80SJiri Pirko 	u64 drops = 0;
2154bbdec80SJiri Pirko 	int err;
2164bbdec80SJiri Pirko 
2174bbdec80SJiri Pirko 	if (devlink->ops->trap_drop_counter_get) {
2184bbdec80SJiri Pirko 		err = devlink->ops->trap_drop_counter_get(devlink,
2194bbdec80SJiri Pirko 							  trap_item->trap,
2204bbdec80SJiri Pirko 							  &drops);
2214bbdec80SJiri Pirko 		if (err)
2224bbdec80SJiri Pirko 			return err;
2234bbdec80SJiri Pirko 	}
2244bbdec80SJiri Pirko 
2254bbdec80SJiri Pirko 	devlink_trap_stats_read(trap_item->stats, &stats);
2264bbdec80SJiri Pirko 
2274bbdec80SJiri Pirko 	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
2284bbdec80SJiri Pirko 	if (!attr)
2294bbdec80SJiri Pirko 		return -EMSGSIZE;
2304bbdec80SJiri Pirko 
2314bbdec80SJiri Pirko 	if (devlink->ops->trap_drop_counter_get &&
232*a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
2334bbdec80SJiri Pirko 		goto nla_put_failure;
2344bbdec80SJiri Pirko 
235*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
236*a788acf1SPrzemek Kitszel 			       u64_stats_read(&stats.rx_packets)))
2374bbdec80SJiri Pirko 		goto nla_put_failure;
2384bbdec80SJiri Pirko 
239*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
240*a788acf1SPrzemek Kitszel 			       u64_stats_read(&stats.rx_bytes)))
2414bbdec80SJiri Pirko 		goto nla_put_failure;
2424bbdec80SJiri Pirko 
2434bbdec80SJiri Pirko 	nla_nest_end(msg, attr);
2444bbdec80SJiri Pirko 
2454bbdec80SJiri Pirko 	return 0;
2464bbdec80SJiri Pirko 
2474bbdec80SJiri Pirko nla_put_failure:
2484bbdec80SJiri Pirko 	nla_nest_cancel(msg, attr);
2494bbdec80SJiri Pirko 	return -EMSGSIZE;
2504bbdec80SJiri Pirko }
2514bbdec80SJiri Pirko 
devlink_nl_trap_fill(struct sk_buff * msg,struct devlink * devlink,const struct devlink_trap_item * trap_item,enum devlink_command cmd,u32 portid,u32 seq,int flags)2524bbdec80SJiri Pirko static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
2534bbdec80SJiri Pirko 				const struct devlink_trap_item *trap_item,
2544bbdec80SJiri Pirko 				enum devlink_command cmd, u32 portid, u32 seq,
2554bbdec80SJiri Pirko 				int flags)
2564bbdec80SJiri Pirko {
2574bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item = trap_item->group_item;
2584bbdec80SJiri Pirko 	void *hdr;
2594bbdec80SJiri Pirko 	int err;
2604bbdec80SJiri Pirko 
2614bbdec80SJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2624bbdec80SJiri Pirko 	if (!hdr)
2634bbdec80SJiri Pirko 		return -EMSGSIZE;
2644bbdec80SJiri Pirko 
2654bbdec80SJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
2664bbdec80SJiri Pirko 		goto nla_put_failure;
2674bbdec80SJiri Pirko 
2684bbdec80SJiri Pirko 	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
2694bbdec80SJiri Pirko 			   group_item->group->name))
2704bbdec80SJiri Pirko 		goto nla_put_failure;
2714bbdec80SJiri Pirko 
2724bbdec80SJiri Pirko 	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
2734bbdec80SJiri Pirko 		goto nla_put_failure;
2744bbdec80SJiri Pirko 
2754bbdec80SJiri Pirko 	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
2764bbdec80SJiri Pirko 		goto nla_put_failure;
2774bbdec80SJiri Pirko 
2784bbdec80SJiri Pirko 	if (trap_item->trap->generic &&
2794bbdec80SJiri Pirko 	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
2804bbdec80SJiri Pirko 		goto nla_put_failure;
2814bbdec80SJiri Pirko 
2824bbdec80SJiri Pirko 	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
2834bbdec80SJiri Pirko 		goto nla_put_failure;
2844bbdec80SJiri Pirko 
2854bbdec80SJiri Pirko 	err = devlink_trap_metadata_put(msg, trap_item->trap);
2864bbdec80SJiri Pirko 	if (err)
2874bbdec80SJiri Pirko 		goto nla_put_failure;
2884bbdec80SJiri Pirko 
2894bbdec80SJiri Pirko 	err = devlink_trap_stats_put(msg, devlink, trap_item);
2904bbdec80SJiri Pirko 	if (err)
2914bbdec80SJiri Pirko 		goto nla_put_failure;
2924bbdec80SJiri Pirko 
2934bbdec80SJiri Pirko 	genlmsg_end(msg, hdr);
2944bbdec80SJiri Pirko 
2954bbdec80SJiri Pirko 	return 0;
2964bbdec80SJiri Pirko 
2974bbdec80SJiri Pirko nla_put_failure:
2984bbdec80SJiri Pirko 	genlmsg_cancel(msg, hdr);
2994bbdec80SJiri Pirko 	return -EMSGSIZE;
3004bbdec80SJiri Pirko }
3014bbdec80SJiri Pirko 
devlink_nl_trap_get_doit(struct sk_buff * skb,struct genl_info * info)3024bbdec80SJiri Pirko int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info)
3034bbdec80SJiri Pirko {
3044bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
3054bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
3064bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
3074bbdec80SJiri Pirko 	struct sk_buff *msg;
3084bbdec80SJiri Pirko 	int err;
3094bbdec80SJiri Pirko 
3104bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_list))
3114bbdec80SJiri Pirko 		return -EOPNOTSUPP;
3124bbdec80SJiri Pirko 
3134bbdec80SJiri Pirko 	trap_item = devlink_trap_item_get_from_info(devlink, info);
3144bbdec80SJiri Pirko 	if (!trap_item) {
3154bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap");
3164bbdec80SJiri Pirko 		return -ENOENT;
3174bbdec80SJiri Pirko 	}
3184bbdec80SJiri Pirko 
3194bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3204bbdec80SJiri Pirko 	if (!msg)
3214bbdec80SJiri Pirko 		return -ENOMEM;
3224bbdec80SJiri Pirko 
3234bbdec80SJiri Pirko 	err = devlink_nl_trap_fill(msg, devlink, trap_item,
3244bbdec80SJiri Pirko 				   DEVLINK_CMD_TRAP_NEW, info->snd_portid,
3254bbdec80SJiri Pirko 				   info->snd_seq, 0);
3264bbdec80SJiri Pirko 	if (err)
3274bbdec80SJiri Pirko 		goto err_trap_fill;
3284bbdec80SJiri Pirko 
3294bbdec80SJiri Pirko 	return genlmsg_reply(msg, info);
3304bbdec80SJiri Pirko 
3314bbdec80SJiri Pirko err_trap_fill:
3324bbdec80SJiri Pirko 	nlmsg_free(msg);
3334bbdec80SJiri Pirko 	return err;
3344bbdec80SJiri Pirko }
3354bbdec80SJiri Pirko 
devlink_nl_trap_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)3364bbdec80SJiri Pirko static int devlink_nl_trap_get_dump_one(struct sk_buff *msg,
3374bbdec80SJiri Pirko 					struct devlink *devlink,
3384bbdec80SJiri Pirko 					struct netlink_callback *cb, int flags)
3394bbdec80SJiri Pirko {
3404bbdec80SJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
3414bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
3424bbdec80SJiri Pirko 	int idx = 0;
3434bbdec80SJiri Pirko 	int err = 0;
3444bbdec80SJiri Pirko 
3454bbdec80SJiri Pirko 	list_for_each_entry(trap_item, &devlink->trap_list, list) {
3464bbdec80SJiri Pirko 		if (idx < state->idx) {
3474bbdec80SJiri Pirko 			idx++;
3484bbdec80SJiri Pirko 			continue;
3494bbdec80SJiri Pirko 		}
3504bbdec80SJiri Pirko 		err = devlink_nl_trap_fill(msg, devlink, trap_item,
3514bbdec80SJiri Pirko 					   DEVLINK_CMD_TRAP_NEW,
3524bbdec80SJiri Pirko 					   NETLINK_CB(cb->skb).portid,
3534bbdec80SJiri Pirko 					   cb->nlh->nlmsg_seq, flags);
3544bbdec80SJiri Pirko 		if (err) {
3554bbdec80SJiri Pirko 			state->idx = idx;
3564bbdec80SJiri Pirko 			break;
3574bbdec80SJiri Pirko 		}
3584bbdec80SJiri Pirko 		idx++;
3594bbdec80SJiri Pirko 	}
3604bbdec80SJiri Pirko 
3614bbdec80SJiri Pirko 	return err;
3624bbdec80SJiri Pirko }
3634bbdec80SJiri Pirko 
devlink_nl_trap_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)3644bbdec80SJiri Pirko int devlink_nl_trap_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
3654bbdec80SJiri Pirko {
3664bbdec80SJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_get_dump_one);
3674bbdec80SJiri Pirko }
3684bbdec80SJiri Pirko 
__devlink_trap_action_set(struct devlink * devlink,struct devlink_trap_item * trap_item,enum devlink_trap_action trap_action,struct netlink_ext_ack * extack)3694bbdec80SJiri Pirko static int __devlink_trap_action_set(struct devlink *devlink,
3704bbdec80SJiri Pirko 				     struct devlink_trap_item *trap_item,
3714bbdec80SJiri Pirko 				     enum devlink_trap_action trap_action,
3724bbdec80SJiri Pirko 				     struct netlink_ext_ack *extack)
3734bbdec80SJiri Pirko {
3744bbdec80SJiri Pirko 	int err;
3754bbdec80SJiri Pirko 
3764bbdec80SJiri Pirko 	if (trap_item->action != trap_action &&
3774bbdec80SJiri Pirko 	    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
3784bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Cannot change action of non-drop traps. Skipping");
3794bbdec80SJiri Pirko 		return 0;
3804bbdec80SJiri Pirko 	}
3814bbdec80SJiri Pirko 
3824bbdec80SJiri Pirko 	err = devlink->ops->trap_action_set(devlink, trap_item->trap,
3834bbdec80SJiri Pirko 					    trap_action, extack);
3844bbdec80SJiri Pirko 	if (err)
3854bbdec80SJiri Pirko 		return err;
3864bbdec80SJiri Pirko 
3874bbdec80SJiri Pirko 	trap_item->action = trap_action;
3884bbdec80SJiri Pirko 
3894bbdec80SJiri Pirko 	return 0;
3904bbdec80SJiri Pirko }
3914bbdec80SJiri Pirko 
devlink_trap_action_set(struct devlink * devlink,struct devlink_trap_item * trap_item,struct genl_info * info)3924bbdec80SJiri Pirko static int devlink_trap_action_set(struct devlink *devlink,
3934bbdec80SJiri Pirko 				   struct devlink_trap_item *trap_item,
3944bbdec80SJiri Pirko 				   struct genl_info *info)
3954bbdec80SJiri Pirko {
3964bbdec80SJiri Pirko 	enum devlink_trap_action trap_action;
3974bbdec80SJiri Pirko 	int err;
3984bbdec80SJiri Pirko 
3994bbdec80SJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
4004bbdec80SJiri Pirko 		return 0;
4014bbdec80SJiri Pirko 
4024bbdec80SJiri Pirko 	err = devlink_trap_action_get_from_info(info, &trap_action);
4034bbdec80SJiri Pirko 	if (err) {
4044bbdec80SJiri Pirko 		NL_SET_ERR_MSG(info->extack, "Invalid trap action");
4054bbdec80SJiri Pirko 		return -EINVAL;
4064bbdec80SJiri Pirko 	}
4074bbdec80SJiri Pirko 
4084bbdec80SJiri Pirko 	return __devlink_trap_action_set(devlink, trap_item, trap_action,
4094bbdec80SJiri Pirko 					 info->extack);
4104bbdec80SJiri Pirko }
4114bbdec80SJiri Pirko 
devlink_nl_trap_set_doit(struct sk_buff * skb,struct genl_info * info)41253590934SJiri Pirko int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info)
4134bbdec80SJiri Pirko {
4144bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
4154bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
4164bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
4174bbdec80SJiri Pirko 
4184bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_list))
4194bbdec80SJiri Pirko 		return -EOPNOTSUPP;
4204bbdec80SJiri Pirko 
4214bbdec80SJiri Pirko 	trap_item = devlink_trap_item_get_from_info(devlink, info);
4224bbdec80SJiri Pirko 	if (!trap_item) {
4234bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap");
4244bbdec80SJiri Pirko 		return -ENOENT;
4254bbdec80SJiri Pirko 	}
4264bbdec80SJiri Pirko 
4274bbdec80SJiri Pirko 	return devlink_trap_action_set(devlink, trap_item, info);
4284bbdec80SJiri Pirko }
4294bbdec80SJiri Pirko 
4304bbdec80SJiri Pirko static struct devlink_trap_group_item *
devlink_trap_group_item_lookup(struct devlink * devlink,const char * name)4314bbdec80SJiri Pirko devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
4324bbdec80SJiri Pirko {
4334bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
4344bbdec80SJiri Pirko 
4354bbdec80SJiri Pirko 	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
4364bbdec80SJiri Pirko 		if (!strcmp(group_item->group->name, name))
4374bbdec80SJiri Pirko 			return group_item;
4384bbdec80SJiri Pirko 	}
4394bbdec80SJiri Pirko 
4404bbdec80SJiri Pirko 	return NULL;
4414bbdec80SJiri Pirko }
4424bbdec80SJiri Pirko 
4434bbdec80SJiri Pirko static struct devlink_trap_group_item *
devlink_trap_group_item_lookup_by_id(struct devlink * devlink,u16 id)4444bbdec80SJiri Pirko devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
4454bbdec80SJiri Pirko {
4464bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
4474bbdec80SJiri Pirko 
4484bbdec80SJiri Pirko 	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
4494bbdec80SJiri Pirko 		if (group_item->group->id == id)
4504bbdec80SJiri Pirko 			return group_item;
4514bbdec80SJiri Pirko 	}
4524bbdec80SJiri Pirko 
4534bbdec80SJiri Pirko 	return NULL;
4544bbdec80SJiri Pirko }
4554bbdec80SJiri Pirko 
4564bbdec80SJiri Pirko static struct devlink_trap_group_item *
devlink_trap_group_item_get_from_info(struct devlink * devlink,struct genl_info * info)4574bbdec80SJiri Pirko devlink_trap_group_item_get_from_info(struct devlink *devlink,
4584bbdec80SJiri Pirko 				      struct genl_info *info)
4594bbdec80SJiri Pirko {
4604bbdec80SJiri Pirko 	char *name;
4614bbdec80SJiri Pirko 
4624bbdec80SJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
4634bbdec80SJiri Pirko 		return NULL;
4644bbdec80SJiri Pirko 	name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
4654bbdec80SJiri Pirko 
4664bbdec80SJiri Pirko 	return devlink_trap_group_item_lookup(devlink, name);
4674bbdec80SJiri Pirko }
4684bbdec80SJiri Pirko 
4694bbdec80SJiri Pirko static int
devlink_nl_trap_group_fill(struct sk_buff * msg,struct devlink * devlink,const struct devlink_trap_group_item * group_item,enum devlink_command cmd,u32 portid,u32 seq,int flags)4704bbdec80SJiri Pirko devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
4714bbdec80SJiri Pirko 			   const struct devlink_trap_group_item *group_item,
4724bbdec80SJiri Pirko 			   enum devlink_command cmd, u32 portid, u32 seq,
4734bbdec80SJiri Pirko 			   int flags)
4744bbdec80SJiri Pirko {
4754bbdec80SJiri Pirko 	void *hdr;
4764bbdec80SJiri Pirko 	int err;
4774bbdec80SJiri Pirko 
4784bbdec80SJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4794bbdec80SJiri Pirko 	if (!hdr)
4804bbdec80SJiri Pirko 		return -EMSGSIZE;
4814bbdec80SJiri Pirko 
4824bbdec80SJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
4834bbdec80SJiri Pirko 		goto nla_put_failure;
4844bbdec80SJiri Pirko 
4854bbdec80SJiri Pirko 	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
4864bbdec80SJiri Pirko 			   group_item->group->name))
4874bbdec80SJiri Pirko 		goto nla_put_failure;
4884bbdec80SJiri Pirko 
4894bbdec80SJiri Pirko 	if (group_item->group->generic &&
4904bbdec80SJiri Pirko 	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
4914bbdec80SJiri Pirko 		goto nla_put_failure;
4924bbdec80SJiri Pirko 
4934bbdec80SJiri Pirko 	if (group_item->policer_item &&
4944bbdec80SJiri Pirko 	    nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
4954bbdec80SJiri Pirko 			group_item->policer_item->policer->id))
4964bbdec80SJiri Pirko 		goto nla_put_failure;
4974bbdec80SJiri Pirko 
4984bbdec80SJiri Pirko 	err = devlink_trap_group_stats_put(msg, group_item->stats);
4994bbdec80SJiri Pirko 	if (err)
5004bbdec80SJiri Pirko 		goto nla_put_failure;
5014bbdec80SJiri Pirko 
5024bbdec80SJiri Pirko 	genlmsg_end(msg, hdr);
5034bbdec80SJiri Pirko 
5044bbdec80SJiri Pirko 	return 0;
5054bbdec80SJiri Pirko 
5064bbdec80SJiri Pirko nla_put_failure:
5074bbdec80SJiri Pirko 	genlmsg_cancel(msg, hdr);
5084bbdec80SJiri Pirko 	return -EMSGSIZE;
5094bbdec80SJiri Pirko }
5104bbdec80SJiri Pirko 
devlink_nl_trap_group_get_doit(struct sk_buff * skb,struct genl_info * info)5114bbdec80SJiri Pirko int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info)
5124bbdec80SJiri Pirko {
5134bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
5144bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
5154bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
5164bbdec80SJiri Pirko 	struct sk_buff *msg;
5174bbdec80SJiri Pirko 	int err;
5184bbdec80SJiri Pirko 
5194bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_group_list))
5204bbdec80SJiri Pirko 		return -EOPNOTSUPP;
5214bbdec80SJiri Pirko 
5224bbdec80SJiri Pirko 	group_item = devlink_trap_group_item_get_from_info(devlink, info);
5234bbdec80SJiri Pirko 	if (!group_item) {
5244bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap group");
5254bbdec80SJiri Pirko 		return -ENOENT;
5264bbdec80SJiri Pirko 	}
5274bbdec80SJiri Pirko 
5284bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5294bbdec80SJiri Pirko 	if (!msg)
5304bbdec80SJiri Pirko 		return -ENOMEM;
5314bbdec80SJiri Pirko 
5324bbdec80SJiri Pirko 	err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5334bbdec80SJiri Pirko 					 DEVLINK_CMD_TRAP_GROUP_NEW,
5344bbdec80SJiri Pirko 					 info->snd_portid, info->snd_seq, 0);
5354bbdec80SJiri Pirko 	if (err)
5364bbdec80SJiri Pirko 		goto err_trap_group_fill;
5374bbdec80SJiri Pirko 
5384bbdec80SJiri Pirko 	return genlmsg_reply(msg, info);
5394bbdec80SJiri Pirko 
5404bbdec80SJiri Pirko err_trap_group_fill:
5414bbdec80SJiri Pirko 	nlmsg_free(msg);
5424bbdec80SJiri Pirko 	return err;
5434bbdec80SJiri Pirko }
5444bbdec80SJiri Pirko 
devlink_nl_trap_group_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)5454bbdec80SJiri Pirko static int devlink_nl_trap_group_get_dump_one(struct sk_buff *msg,
5464bbdec80SJiri Pirko 					      struct devlink *devlink,
5474bbdec80SJiri Pirko 					      struct netlink_callback *cb,
5484bbdec80SJiri Pirko 					      int flags)
5494bbdec80SJiri Pirko {
5504bbdec80SJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
5514bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
5524bbdec80SJiri Pirko 	int idx = 0;
5534bbdec80SJiri Pirko 	int err = 0;
5544bbdec80SJiri Pirko 
5554bbdec80SJiri Pirko 	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
5564bbdec80SJiri Pirko 		if (idx < state->idx) {
5574bbdec80SJiri Pirko 			idx++;
5584bbdec80SJiri Pirko 			continue;
5594bbdec80SJiri Pirko 		}
5604bbdec80SJiri Pirko 		err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5614bbdec80SJiri Pirko 						 DEVLINK_CMD_TRAP_GROUP_NEW,
5624bbdec80SJiri Pirko 						 NETLINK_CB(cb->skb).portid,
5634bbdec80SJiri Pirko 						 cb->nlh->nlmsg_seq, flags);
5644bbdec80SJiri Pirko 		if (err) {
5654bbdec80SJiri Pirko 			state->idx = idx;
5664bbdec80SJiri Pirko 			break;
5674bbdec80SJiri Pirko 		}
5684bbdec80SJiri Pirko 		idx++;
5694bbdec80SJiri Pirko 	}
5704bbdec80SJiri Pirko 
5714bbdec80SJiri Pirko 	return err;
5724bbdec80SJiri Pirko }
5734bbdec80SJiri Pirko 
devlink_nl_trap_group_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)5744bbdec80SJiri Pirko int devlink_nl_trap_group_get_dumpit(struct sk_buff *skb,
5754bbdec80SJiri Pirko 				     struct netlink_callback *cb)
5764bbdec80SJiri Pirko {
5774bbdec80SJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_group_get_dump_one);
5784bbdec80SJiri Pirko }
5794bbdec80SJiri Pirko 
5804bbdec80SJiri Pirko static int
__devlink_trap_group_action_set(struct devlink * devlink,struct devlink_trap_group_item * group_item,enum devlink_trap_action trap_action,struct netlink_ext_ack * extack)5814bbdec80SJiri Pirko __devlink_trap_group_action_set(struct devlink *devlink,
5824bbdec80SJiri Pirko 				struct devlink_trap_group_item *group_item,
5834bbdec80SJiri Pirko 				enum devlink_trap_action trap_action,
5844bbdec80SJiri Pirko 				struct netlink_ext_ack *extack)
5854bbdec80SJiri Pirko {
5864bbdec80SJiri Pirko 	const char *group_name = group_item->group->name;
5874bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
5884bbdec80SJiri Pirko 	int err;
5894bbdec80SJiri Pirko 
5904bbdec80SJiri Pirko 	if (devlink->ops->trap_group_action_set) {
5914bbdec80SJiri Pirko 		err = devlink->ops->trap_group_action_set(devlink, group_item->group,
5924bbdec80SJiri Pirko 							  trap_action, extack);
5934bbdec80SJiri Pirko 		if (err)
5944bbdec80SJiri Pirko 			return err;
5954bbdec80SJiri Pirko 
5964bbdec80SJiri Pirko 		list_for_each_entry(trap_item, &devlink->trap_list, list) {
5974bbdec80SJiri Pirko 			if (strcmp(trap_item->group_item->group->name, group_name))
5984bbdec80SJiri Pirko 				continue;
5994bbdec80SJiri Pirko 			if (trap_item->action != trap_action &&
6004bbdec80SJiri Pirko 			    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
6014bbdec80SJiri Pirko 				continue;
6024bbdec80SJiri Pirko 			trap_item->action = trap_action;
6034bbdec80SJiri Pirko 		}
6044bbdec80SJiri Pirko 
6054bbdec80SJiri Pirko 		return 0;
6064bbdec80SJiri Pirko 	}
6074bbdec80SJiri Pirko 
6084bbdec80SJiri Pirko 	list_for_each_entry(trap_item, &devlink->trap_list, list) {
6094bbdec80SJiri Pirko 		if (strcmp(trap_item->group_item->group->name, group_name))
6104bbdec80SJiri Pirko 			continue;
6114bbdec80SJiri Pirko 		err = __devlink_trap_action_set(devlink, trap_item,
6124bbdec80SJiri Pirko 						trap_action, extack);
6134bbdec80SJiri Pirko 		if (err)
6144bbdec80SJiri Pirko 			return err;
6154bbdec80SJiri Pirko 	}
6164bbdec80SJiri Pirko 
6174bbdec80SJiri Pirko 	return 0;
6184bbdec80SJiri Pirko }
6194bbdec80SJiri Pirko 
6204bbdec80SJiri Pirko static int
devlink_trap_group_action_set(struct devlink * devlink,struct devlink_trap_group_item * group_item,struct genl_info * info,bool * p_modified)6214bbdec80SJiri Pirko devlink_trap_group_action_set(struct devlink *devlink,
6224bbdec80SJiri Pirko 			      struct devlink_trap_group_item *group_item,
6234bbdec80SJiri Pirko 			      struct genl_info *info, bool *p_modified)
6244bbdec80SJiri Pirko {
6254bbdec80SJiri Pirko 	enum devlink_trap_action trap_action;
6264bbdec80SJiri Pirko 	int err;
6274bbdec80SJiri Pirko 
6284bbdec80SJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6294bbdec80SJiri Pirko 		return 0;
6304bbdec80SJiri Pirko 
6314bbdec80SJiri Pirko 	err = devlink_trap_action_get_from_info(info, &trap_action);
6324bbdec80SJiri Pirko 	if (err) {
6334bbdec80SJiri Pirko 		NL_SET_ERR_MSG(info->extack, "Invalid trap action");
6344bbdec80SJiri Pirko 		return -EINVAL;
6354bbdec80SJiri Pirko 	}
6364bbdec80SJiri Pirko 
6374bbdec80SJiri Pirko 	err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6384bbdec80SJiri Pirko 					      info->extack);
6394bbdec80SJiri Pirko 	if (err)
6404bbdec80SJiri Pirko 		return err;
6414bbdec80SJiri Pirko 
6424bbdec80SJiri Pirko 	*p_modified = true;
6434bbdec80SJiri Pirko 
6444bbdec80SJiri Pirko 	return 0;
6454bbdec80SJiri Pirko }
6464bbdec80SJiri Pirko 
devlink_trap_group_set(struct devlink * devlink,struct devlink_trap_group_item * group_item,struct genl_info * info)6474bbdec80SJiri Pirko static int devlink_trap_group_set(struct devlink *devlink,
6484bbdec80SJiri Pirko 				  struct devlink_trap_group_item *group_item,
6494bbdec80SJiri Pirko 				  struct genl_info *info)
6504bbdec80SJiri Pirko {
6514bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
6524bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
6534bbdec80SJiri Pirko 	const struct devlink_trap_policer *policer;
6544bbdec80SJiri Pirko 	struct nlattr **attrs = info->attrs;
6554bbdec80SJiri Pirko 	u32 policer_id;
6564bbdec80SJiri Pirko 	int err;
6574bbdec80SJiri Pirko 
6584bbdec80SJiri Pirko 	if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6594bbdec80SJiri Pirko 		return 0;
6604bbdec80SJiri Pirko 
6614bbdec80SJiri Pirko 	if (!devlink->ops->trap_group_set)
6624bbdec80SJiri Pirko 		return -EOPNOTSUPP;
6634bbdec80SJiri Pirko 
6644bbdec80SJiri Pirko 	policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6654bbdec80SJiri Pirko 	policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
6664bbdec80SJiri Pirko 	if (policer_id && !policer_item) {
6674bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
6684bbdec80SJiri Pirko 		return -ENOENT;
6694bbdec80SJiri Pirko 	}
6704bbdec80SJiri Pirko 	policer = policer_item ? policer_item->policer : NULL;
6714bbdec80SJiri Pirko 
6724bbdec80SJiri Pirko 	err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
6734bbdec80SJiri Pirko 					   extack);
6744bbdec80SJiri Pirko 	if (err)
6754bbdec80SJiri Pirko 		return err;
6764bbdec80SJiri Pirko 
6774bbdec80SJiri Pirko 	group_item->policer_item = policer_item;
6784bbdec80SJiri Pirko 
6794bbdec80SJiri Pirko 	return 0;
6804bbdec80SJiri Pirko }
6814bbdec80SJiri Pirko 
devlink_nl_trap_group_set_doit(struct sk_buff * skb,struct genl_info * info)68253590934SJiri Pirko int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info)
6834bbdec80SJiri Pirko {
6844bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
6854bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
6864bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
6874bbdec80SJiri Pirko 	bool modified = false;
6884bbdec80SJiri Pirko 	int err;
6894bbdec80SJiri Pirko 
6904bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_group_list))
6914bbdec80SJiri Pirko 		return -EOPNOTSUPP;
6924bbdec80SJiri Pirko 
6934bbdec80SJiri Pirko 	group_item = devlink_trap_group_item_get_from_info(devlink, info);
6944bbdec80SJiri Pirko 	if (!group_item) {
6954bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap group");
6964bbdec80SJiri Pirko 		return -ENOENT;
6974bbdec80SJiri Pirko 	}
6984bbdec80SJiri Pirko 
6994bbdec80SJiri Pirko 	err = devlink_trap_group_action_set(devlink, group_item, info,
7004bbdec80SJiri Pirko 					    &modified);
7014bbdec80SJiri Pirko 	if (err)
7024bbdec80SJiri Pirko 		return err;
7034bbdec80SJiri Pirko 
7044bbdec80SJiri Pirko 	err = devlink_trap_group_set(devlink, group_item, info);
7054bbdec80SJiri Pirko 	if (err)
7064bbdec80SJiri Pirko 		goto err_trap_group_set;
7074bbdec80SJiri Pirko 
7084bbdec80SJiri Pirko 	return 0;
7094bbdec80SJiri Pirko 
7104bbdec80SJiri Pirko err_trap_group_set:
7114bbdec80SJiri Pirko 	if (modified)
7124bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Trap group set failed, but some changes were committed already");
7134bbdec80SJiri Pirko 	return err;
7144bbdec80SJiri Pirko }
7154bbdec80SJiri Pirko 
7164bbdec80SJiri Pirko static struct devlink_trap_policer_item *
devlink_trap_policer_item_get_from_info(struct devlink * devlink,struct genl_info * info)7174bbdec80SJiri Pirko devlink_trap_policer_item_get_from_info(struct devlink *devlink,
7184bbdec80SJiri Pirko 					struct genl_info *info)
7194bbdec80SJiri Pirko {
7204bbdec80SJiri Pirko 	u32 id;
7214bbdec80SJiri Pirko 
7224bbdec80SJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7234bbdec80SJiri Pirko 		return NULL;
7244bbdec80SJiri Pirko 	id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7254bbdec80SJiri Pirko 
7264bbdec80SJiri Pirko 	return devlink_trap_policer_item_lookup(devlink, id);
7274bbdec80SJiri Pirko }
7284bbdec80SJiri Pirko 
7294bbdec80SJiri Pirko static int
devlink_trap_policer_stats_put(struct sk_buff * msg,struct devlink * devlink,const struct devlink_trap_policer * policer)7304bbdec80SJiri Pirko devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
7314bbdec80SJiri Pirko 			       const struct devlink_trap_policer *policer)
7324bbdec80SJiri Pirko {
7334bbdec80SJiri Pirko 	struct nlattr *attr;
7344bbdec80SJiri Pirko 	u64 drops;
7354bbdec80SJiri Pirko 	int err;
7364bbdec80SJiri Pirko 
7374bbdec80SJiri Pirko 	if (!devlink->ops->trap_policer_counter_get)
7384bbdec80SJiri Pirko 		return 0;
7394bbdec80SJiri Pirko 
7404bbdec80SJiri Pirko 	err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
7414bbdec80SJiri Pirko 	if (err)
7424bbdec80SJiri Pirko 		return err;
7434bbdec80SJiri Pirko 
7444bbdec80SJiri Pirko 	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
7454bbdec80SJiri Pirko 	if (!attr)
7464bbdec80SJiri Pirko 		return -EMSGSIZE;
7474bbdec80SJiri Pirko 
748*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
7494bbdec80SJiri Pirko 		goto nla_put_failure;
7504bbdec80SJiri Pirko 
7514bbdec80SJiri Pirko 	nla_nest_end(msg, attr);
7524bbdec80SJiri Pirko 
7534bbdec80SJiri Pirko 	return 0;
7544bbdec80SJiri Pirko 
7554bbdec80SJiri Pirko nla_put_failure:
7564bbdec80SJiri Pirko 	nla_nest_cancel(msg, attr);
7574bbdec80SJiri Pirko 	return -EMSGSIZE;
7584bbdec80SJiri Pirko }
7594bbdec80SJiri Pirko 
7604bbdec80SJiri Pirko static int
devlink_nl_trap_policer_fill(struct sk_buff * msg,struct devlink * devlink,const struct devlink_trap_policer_item * policer_item,enum devlink_command cmd,u32 portid,u32 seq,int flags)7614bbdec80SJiri Pirko devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
7624bbdec80SJiri Pirko 			     const struct devlink_trap_policer_item *policer_item,
7634bbdec80SJiri Pirko 			     enum devlink_command cmd, u32 portid, u32 seq,
7644bbdec80SJiri Pirko 			     int flags)
7654bbdec80SJiri Pirko {
7664bbdec80SJiri Pirko 	void *hdr;
7674bbdec80SJiri Pirko 	int err;
7684bbdec80SJiri Pirko 
7694bbdec80SJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7704bbdec80SJiri Pirko 	if (!hdr)
7714bbdec80SJiri Pirko 		return -EMSGSIZE;
7724bbdec80SJiri Pirko 
7734bbdec80SJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
7744bbdec80SJiri Pirko 		goto nla_put_failure;
7754bbdec80SJiri Pirko 
7764bbdec80SJiri Pirko 	if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7774bbdec80SJiri Pirko 			policer_item->policer->id))
7784bbdec80SJiri Pirko 		goto nla_put_failure;
7794bbdec80SJiri Pirko 
780*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
781*a788acf1SPrzemek Kitszel 			       policer_item->rate))
7824bbdec80SJiri Pirko 		goto nla_put_failure;
7834bbdec80SJiri Pirko 
784*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
785*a788acf1SPrzemek Kitszel 			       policer_item->burst))
7864bbdec80SJiri Pirko 		goto nla_put_failure;
7874bbdec80SJiri Pirko 
7884bbdec80SJiri Pirko 	err = devlink_trap_policer_stats_put(msg, devlink,
7894bbdec80SJiri Pirko 					     policer_item->policer);
7904bbdec80SJiri Pirko 	if (err)
7914bbdec80SJiri Pirko 		goto nla_put_failure;
7924bbdec80SJiri Pirko 
7934bbdec80SJiri Pirko 	genlmsg_end(msg, hdr);
7944bbdec80SJiri Pirko 
7954bbdec80SJiri Pirko 	return 0;
7964bbdec80SJiri Pirko 
7974bbdec80SJiri Pirko nla_put_failure:
7984bbdec80SJiri Pirko 	genlmsg_cancel(msg, hdr);
7994bbdec80SJiri Pirko 	return -EMSGSIZE;
8004bbdec80SJiri Pirko }
8014bbdec80SJiri Pirko 
devlink_nl_trap_policer_get_doit(struct sk_buff * skb,struct genl_info * info)8024bbdec80SJiri Pirko int devlink_nl_trap_policer_get_doit(struct sk_buff *skb,
8034bbdec80SJiri Pirko 				     struct genl_info *info)
8044bbdec80SJiri Pirko {
8054bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
8064bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
8074bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
8084bbdec80SJiri Pirko 	struct sk_buff *msg;
8094bbdec80SJiri Pirko 	int err;
8104bbdec80SJiri Pirko 
8114bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_policer_list))
8124bbdec80SJiri Pirko 		return -EOPNOTSUPP;
8134bbdec80SJiri Pirko 
8144bbdec80SJiri Pirko 	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
8154bbdec80SJiri Pirko 	if (!policer_item) {
8164bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
8174bbdec80SJiri Pirko 		return -ENOENT;
8184bbdec80SJiri Pirko 	}
8194bbdec80SJiri Pirko 
8204bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8214bbdec80SJiri Pirko 	if (!msg)
8224bbdec80SJiri Pirko 		return -ENOMEM;
8234bbdec80SJiri Pirko 
8244bbdec80SJiri Pirko 	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
8254bbdec80SJiri Pirko 					   DEVLINK_CMD_TRAP_POLICER_NEW,
8264bbdec80SJiri Pirko 					   info->snd_portid, info->snd_seq, 0);
8274bbdec80SJiri Pirko 	if (err)
8284bbdec80SJiri Pirko 		goto err_trap_policer_fill;
8294bbdec80SJiri Pirko 
8304bbdec80SJiri Pirko 	return genlmsg_reply(msg, info);
8314bbdec80SJiri Pirko 
8324bbdec80SJiri Pirko err_trap_policer_fill:
8334bbdec80SJiri Pirko 	nlmsg_free(msg);
8344bbdec80SJiri Pirko 	return err;
8354bbdec80SJiri Pirko }
8364bbdec80SJiri Pirko 
devlink_nl_trap_policer_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)8374bbdec80SJiri Pirko static int devlink_nl_trap_policer_get_dump_one(struct sk_buff *msg,
8384bbdec80SJiri Pirko 						struct devlink *devlink,
8394bbdec80SJiri Pirko 						struct netlink_callback *cb,
8404bbdec80SJiri Pirko 						int flags)
8414bbdec80SJiri Pirko {
8424bbdec80SJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
8434bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
8444bbdec80SJiri Pirko 	int idx = 0;
8454bbdec80SJiri Pirko 	int err = 0;
8464bbdec80SJiri Pirko 
8474bbdec80SJiri Pirko 	list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
8484bbdec80SJiri Pirko 		if (idx < state->idx) {
8494bbdec80SJiri Pirko 			idx++;
8504bbdec80SJiri Pirko 			continue;
8514bbdec80SJiri Pirko 		}
8524bbdec80SJiri Pirko 		err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
8534bbdec80SJiri Pirko 						   DEVLINK_CMD_TRAP_POLICER_NEW,
8544bbdec80SJiri Pirko 						   NETLINK_CB(cb->skb).portid,
8554bbdec80SJiri Pirko 						   cb->nlh->nlmsg_seq, flags);
8564bbdec80SJiri Pirko 		if (err) {
8574bbdec80SJiri Pirko 			state->idx = idx;
8584bbdec80SJiri Pirko 			break;
8594bbdec80SJiri Pirko 		}
8604bbdec80SJiri Pirko 		idx++;
8614bbdec80SJiri Pirko 	}
8624bbdec80SJiri Pirko 
8634bbdec80SJiri Pirko 	return err;
8644bbdec80SJiri Pirko }
8654bbdec80SJiri Pirko 
devlink_nl_trap_policer_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)8664bbdec80SJiri Pirko int devlink_nl_trap_policer_get_dumpit(struct sk_buff *skb,
8674bbdec80SJiri Pirko 				       struct netlink_callback *cb)
8684bbdec80SJiri Pirko {
8694bbdec80SJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_policer_get_dump_one);
8704bbdec80SJiri Pirko }
8714bbdec80SJiri Pirko 
8724bbdec80SJiri Pirko static int
devlink_trap_policer_set(struct devlink * devlink,struct devlink_trap_policer_item * policer_item,struct genl_info * info)8734bbdec80SJiri Pirko devlink_trap_policer_set(struct devlink *devlink,
8744bbdec80SJiri Pirko 			 struct devlink_trap_policer_item *policer_item,
8754bbdec80SJiri Pirko 			 struct genl_info *info)
8764bbdec80SJiri Pirko {
8774bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
8784bbdec80SJiri Pirko 	struct nlattr **attrs = info->attrs;
8794bbdec80SJiri Pirko 	u64 rate, burst;
8804bbdec80SJiri Pirko 	int err;
8814bbdec80SJiri Pirko 
8824bbdec80SJiri Pirko 	rate = policer_item->rate;
8834bbdec80SJiri Pirko 	burst = policer_item->burst;
8844bbdec80SJiri Pirko 
8854bbdec80SJiri Pirko 	if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
8864bbdec80SJiri Pirko 		rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
8874bbdec80SJiri Pirko 
8884bbdec80SJiri Pirko 	if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
8894bbdec80SJiri Pirko 		burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
8904bbdec80SJiri Pirko 
8914bbdec80SJiri Pirko 	if (rate < policer_item->policer->min_rate) {
8924bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Policer rate lower than limit");
8934bbdec80SJiri Pirko 		return -EINVAL;
8944bbdec80SJiri Pirko 	}
8954bbdec80SJiri Pirko 
8964bbdec80SJiri Pirko 	if (rate > policer_item->policer->max_rate) {
8974bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Policer rate higher than limit");
8984bbdec80SJiri Pirko 		return -EINVAL;
8994bbdec80SJiri Pirko 	}
9004bbdec80SJiri Pirko 
9014bbdec80SJiri Pirko 	if (burst < policer_item->policer->min_burst) {
9024bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Policer burst size lower than limit");
9034bbdec80SJiri Pirko 		return -EINVAL;
9044bbdec80SJiri Pirko 	}
9054bbdec80SJiri Pirko 
9064bbdec80SJiri Pirko 	if (burst > policer_item->policer->max_burst) {
9074bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Policer burst size higher than limit");
9084bbdec80SJiri Pirko 		return -EINVAL;
9094bbdec80SJiri Pirko 	}
9104bbdec80SJiri Pirko 
9114bbdec80SJiri Pirko 	err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
9124bbdec80SJiri Pirko 					     rate, burst, info->extack);
9134bbdec80SJiri Pirko 	if (err)
9144bbdec80SJiri Pirko 		return err;
9154bbdec80SJiri Pirko 
9164bbdec80SJiri Pirko 	policer_item->rate = rate;
9174bbdec80SJiri Pirko 	policer_item->burst = burst;
9184bbdec80SJiri Pirko 
9194bbdec80SJiri Pirko 	return 0;
9204bbdec80SJiri Pirko }
9214bbdec80SJiri Pirko 
devlink_nl_trap_policer_set_doit(struct sk_buff * skb,struct genl_info * info)92253590934SJiri Pirko int devlink_nl_trap_policer_set_doit(struct sk_buff *skb,
9234bbdec80SJiri Pirko 				     struct genl_info *info)
9244bbdec80SJiri Pirko {
9254bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
9264bbdec80SJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
9274bbdec80SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
9284bbdec80SJiri Pirko 
9294bbdec80SJiri Pirko 	if (list_empty(&devlink->trap_policer_list))
9304bbdec80SJiri Pirko 		return -EOPNOTSUPP;
9314bbdec80SJiri Pirko 
9324bbdec80SJiri Pirko 	if (!devlink->ops->trap_policer_set)
9334bbdec80SJiri Pirko 		return -EOPNOTSUPP;
9344bbdec80SJiri Pirko 
9354bbdec80SJiri Pirko 	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
9364bbdec80SJiri Pirko 	if (!policer_item) {
9374bbdec80SJiri Pirko 		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
9384bbdec80SJiri Pirko 		return -ENOENT;
9394bbdec80SJiri Pirko 	}
9404bbdec80SJiri Pirko 
9414bbdec80SJiri Pirko 	return devlink_trap_policer_set(devlink, policer_item, info);
9424bbdec80SJiri Pirko }
9434bbdec80SJiri Pirko 
9444bbdec80SJiri Pirko #define DEVLINK_TRAP(_id, _type)					      \
9454bbdec80SJiri Pirko 	{								      \
9464bbdec80SJiri Pirko 		.type = DEVLINK_TRAP_TYPE_##_type,			      \
9474bbdec80SJiri Pirko 		.id = DEVLINK_TRAP_GENERIC_ID_##_id,			      \
9484bbdec80SJiri Pirko 		.name = DEVLINK_TRAP_GENERIC_NAME_##_id,		      \
9494bbdec80SJiri Pirko 	}
9504bbdec80SJiri Pirko 
9514bbdec80SJiri Pirko static const struct devlink_trap devlink_trap_generic[] = {
9524bbdec80SJiri Pirko 	DEVLINK_TRAP(SMAC_MC, DROP),
9534bbdec80SJiri Pirko 	DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
9544bbdec80SJiri Pirko 	DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
9554bbdec80SJiri Pirko 	DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
9564bbdec80SJiri Pirko 	DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
9574bbdec80SJiri Pirko 	DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
9584bbdec80SJiri Pirko 	DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
9594bbdec80SJiri Pirko 	DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
9604bbdec80SJiri Pirko 	DEVLINK_TRAP(TAIL_DROP, DROP),
9614bbdec80SJiri Pirko 	DEVLINK_TRAP(NON_IP_PACKET, DROP),
9624bbdec80SJiri Pirko 	DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
9634bbdec80SJiri Pirko 	DEVLINK_TRAP(DIP_LB, DROP),
9644bbdec80SJiri Pirko 	DEVLINK_TRAP(SIP_MC, DROP),
9654bbdec80SJiri Pirko 	DEVLINK_TRAP(SIP_LB, DROP),
9664bbdec80SJiri Pirko 	DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
9674bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_SIP_BC, DROP),
9684bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
9694bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
9704bbdec80SJiri Pirko 	DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
9714bbdec80SJiri Pirko 	DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
9724bbdec80SJiri Pirko 	DEVLINK_TRAP(RPF, EXCEPTION),
9734bbdec80SJiri Pirko 	DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
9744bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
9754bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
9764bbdec80SJiri Pirko 	DEVLINK_TRAP(NON_ROUTABLE, DROP),
9774bbdec80SJiri Pirko 	DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
9784bbdec80SJiri Pirko 	DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
9794bbdec80SJiri Pirko 	DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
9804bbdec80SJiri Pirko 	DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
9814bbdec80SJiri Pirko 	DEVLINK_TRAP(STP, CONTROL),
9824bbdec80SJiri Pirko 	DEVLINK_TRAP(LACP, CONTROL),
9834bbdec80SJiri Pirko 	DEVLINK_TRAP(LLDP, CONTROL),
9844bbdec80SJiri Pirko 	DEVLINK_TRAP(IGMP_QUERY, CONTROL),
9854bbdec80SJiri Pirko 	DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
9864bbdec80SJiri Pirko 	DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
9874bbdec80SJiri Pirko 	DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
9884bbdec80SJiri Pirko 	DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
9894bbdec80SJiri Pirko 	DEVLINK_TRAP(MLD_QUERY, CONTROL),
9904bbdec80SJiri Pirko 	DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
9914bbdec80SJiri Pirko 	DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
9924bbdec80SJiri Pirko 	DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
9934bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_DHCP, CONTROL),
9944bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_DHCP, CONTROL),
9954bbdec80SJiri Pirko 	DEVLINK_TRAP(ARP_REQUEST, CONTROL),
9964bbdec80SJiri Pirko 	DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
9974bbdec80SJiri Pirko 	DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
9984bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
9994bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
10004bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_BFD, CONTROL),
10014bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_BFD, CONTROL),
10024bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_OSPF, CONTROL),
10034bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_OSPF, CONTROL),
10044bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_BGP, CONTROL),
10054bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_BGP, CONTROL),
10064bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_VRRP, CONTROL),
10074bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_VRRP, CONTROL),
10084bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_PIM, CONTROL),
10094bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_PIM, CONTROL),
10104bbdec80SJiri Pirko 	DEVLINK_TRAP(UC_LB, CONTROL),
10114bbdec80SJiri Pirko 	DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
10124bbdec80SJiri Pirko 	DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
10134bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
10144bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
10154bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
10164bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
10174bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
10184bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
10194bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
10204bbdec80SJiri Pirko 	DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
10214bbdec80SJiri Pirko 	DEVLINK_TRAP(PTP_EVENT, CONTROL),
10224bbdec80SJiri Pirko 	DEVLINK_TRAP(PTP_GENERAL, CONTROL),
10234bbdec80SJiri Pirko 	DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
10244bbdec80SJiri Pirko 	DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
10254bbdec80SJiri Pirko 	DEVLINK_TRAP(EARLY_DROP, DROP),
10264bbdec80SJiri Pirko 	DEVLINK_TRAP(VXLAN_PARSING, DROP),
10274bbdec80SJiri Pirko 	DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
10284bbdec80SJiri Pirko 	DEVLINK_TRAP(VLAN_PARSING, DROP),
10294bbdec80SJiri Pirko 	DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
10304bbdec80SJiri Pirko 	DEVLINK_TRAP(MPLS_PARSING, DROP),
10314bbdec80SJiri Pirko 	DEVLINK_TRAP(ARP_PARSING, DROP),
10324bbdec80SJiri Pirko 	DEVLINK_TRAP(IP_1_PARSING, DROP),
10334bbdec80SJiri Pirko 	DEVLINK_TRAP(IP_N_PARSING, DROP),
10344bbdec80SJiri Pirko 	DEVLINK_TRAP(GRE_PARSING, DROP),
10354bbdec80SJiri Pirko 	DEVLINK_TRAP(UDP_PARSING, DROP),
10364bbdec80SJiri Pirko 	DEVLINK_TRAP(TCP_PARSING, DROP),
10374bbdec80SJiri Pirko 	DEVLINK_TRAP(IPSEC_PARSING, DROP),
10384bbdec80SJiri Pirko 	DEVLINK_TRAP(SCTP_PARSING, DROP),
10394bbdec80SJiri Pirko 	DEVLINK_TRAP(DCCP_PARSING, DROP),
10404bbdec80SJiri Pirko 	DEVLINK_TRAP(GTP_PARSING, DROP),
10414bbdec80SJiri Pirko 	DEVLINK_TRAP(ESP_PARSING, DROP),
10424bbdec80SJiri Pirko 	DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP),
10434bbdec80SJiri Pirko 	DEVLINK_TRAP(DMAC_FILTER, DROP),
10444bbdec80SJiri Pirko 	DEVLINK_TRAP(EAPOL, CONTROL),
10454bbdec80SJiri Pirko 	DEVLINK_TRAP(LOCKED_PORT, DROP),
10464bbdec80SJiri Pirko };
10474bbdec80SJiri Pirko 
10484bbdec80SJiri Pirko #define DEVLINK_TRAP_GROUP(_id)						      \
10494bbdec80SJiri Pirko 	{								      \
10504bbdec80SJiri Pirko 		.id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id,		      \
10514bbdec80SJiri Pirko 		.name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id,		      \
10524bbdec80SJiri Pirko 	}
10534bbdec80SJiri Pirko 
10544bbdec80SJiri Pirko static const struct devlink_trap_group devlink_trap_group_generic[] = {
10554bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(L2_DROPS),
10564bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(L3_DROPS),
10574bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
10584bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(BUFFER_DROPS),
10594bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
10604bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(ACL_DROPS),
10614bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(STP),
10624bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(LACP),
10634bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(LLDP),
10644bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(MC_SNOOPING),
10654bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(DHCP),
10664bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
10674bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(BFD),
10684bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(OSPF),
10694bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(BGP),
10704bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(VRRP),
10714bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(PIM),
10724bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(UC_LB),
10734bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
10744bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
10754bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(IPV6),
10764bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(PTP_EVENT),
10774bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(PTP_GENERAL),
10784bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(ACL_SAMPLE),
10794bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(ACL_TRAP),
10804bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
10814bbdec80SJiri Pirko 	DEVLINK_TRAP_GROUP(EAPOL),
10824bbdec80SJiri Pirko };
10834bbdec80SJiri Pirko 
devlink_trap_generic_verify(const struct devlink_trap * trap)10844bbdec80SJiri Pirko static int devlink_trap_generic_verify(const struct devlink_trap *trap)
10854bbdec80SJiri Pirko {
10864bbdec80SJiri Pirko 	if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
10874bbdec80SJiri Pirko 		return -EINVAL;
10884bbdec80SJiri Pirko 
10894bbdec80SJiri Pirko 	if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
10904bbdec80SJiri Pirko 		return -EINVAL;
10914bbdec80SJiri Pirko 
10924bbdec80SJiri Pirko 	if (trap->type != devlink_trap_generic[trap->id].type)
10934bbdec80SJiri Pirko 		return -EINVAL;
10944bbdec80SJiri Pirko 
10954bbdec80SJiri Pirko 	return 0;
10964bbdec80SJiri Pirko }
10974bbdec80SJiri Pirko 
devlink_trap_driver_verify(const struct devlink_trap * trap)10984bbdec80SJiri Pirko static int devlink_trap_driver_verify(const struct devlink_trap *trap)
10994bbdec80SJiri Pirko {
11004bbdec80SJiri Pirko 	int i;
11014bbdec80SJiri Pirko 
11024bbdec80SJiri Pirko 	if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
11034bbdec80SJiri Pirko 		return -EINVAL;
11044bbdec80SJiri Pirko 
11054bbdec80SJiri Pirko 	for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
11064bbdec80SJiri Pirko 		if (!strcmp(trap->name, devlink_trap_generic[i].name))
11074bbdec80SJiri Pirko 			return -EEXIST;
11084bbdec80SJiri Pirko 	}
11094bbdec80SJiri Pirko 
11104bbdec80SJiri Pirko 	return 0;
11114bbdec80SJiri Pirko }
11124bbdec80SJiri Pirko 
devlink_trap_verify(const struct devlink_trap * trap)11134bbdec80SJiri Pirko static int devlink_trap_verify(const struct devlink_trap *trap)
11144bbdec80SJiri Pirko {
11154bbdec80SJiri Pirko 	if (!trap || !trap->name)
11164bbdec80SJiri Pirko 		return -EINVAL;
11174bbdec80SJiri Pirko 
11184bbdec80SJiri Pirko 	if (trap->generic)
11194bbdec80SJiri Pirko 		return devlink_trap_generic_verify(trap);
11204bbdec80SJiri Pirko 	else
11214bbdec80SJiri Pirko 		return devlink_trap_driver_verify(trap);
11224bbdec80SJiri Pirko }
11234bbdec80SJiri Pirko 
11244bbdec80SJiri Pirko static int
devlink_trap_group_generic_verify(const struct devlink_trap_group * group)11254bbdec80SJiri Pirko devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
11264bbdec80SJiri Pirko {
11274bbdec80SJiri Pirko 	if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
11284bbdec80SJiri Pirko 		return -EINVAL;
11294bbdec80SJiri Pirko 
11304bbdec80SJiri Pirko 	if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
11314bbdec80SJiri Pirko 		return -EINVAL;
11324bbdec80SJiri Pirko 
11334bbdec80SJiri Pirko 	return 0;
11344bbdec80SJiri Pirko }
11354bbdec80SJiri Pirko 
11364bbdec80SJiri Pirko static int
devlink_trap_group_driver_verify(const struct devlink_trap_group * group)11374bbdec80SJiri Pirko devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
11384bbdec80SJiri Pirko {
11394bbdec80SJiri Pirko 	int i;
11404bbdec80SJiri Pirko 
11414bbdec80SJiri Pirko 	if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
11424bbdec80SJiri Pirko 		return -EINVAL;
11434bbdec80SJiri Pirko 
11444bbdec80SJiri Pirko 	for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
11454bbdec80SJiri Pirko 		if (!strcmp(group->name, devlink_trap_group_generic[i].name))
11464bbdec80SJiri Pirko 			return -EEXIST;
11474bbdec80SJiri Pirko 	}
11484bbdec80SJiri Pirko 
11494bbdec80SJiri Pirko 	return 0;
11504bbdec80SJiri Pirko }
11514bbdec80SJiri Pirko 
devlink_trap_group_verify(const struct devlink_trap_group * group)11524bbdec80SJiri Pirko static int devlink_trap_group_verify(const struct devlink_trap_group *group)
11534bbdec80SJiri Pirko {
11544bbdec80SJiri Pirko 	if (group->generic)
11554bbdec80SJiri Pirko 		return devlink_trap_group_generic_verify(group);
11564bbdec80SJiri Pirko 	else
11574bbdec80SJiri Pirko 		return devlink_trap_group_driver_verify(group);
11584bbdec80SJiri Pirko }
11594bbdec80SJiri Pirko 
11604bbdec80SJiri Pirko static void
devlink_trap_group_notify(struct devlink * devlink,const struct devlink_trap_group_item * group_item,enum devlink_command cmd)11614bbdec80SJiri Pirko devlink_trap_group_notify(struct devlink *devlink,
11624bbdec80SJiri Pirko 			  const struct devlink_trap_group_item *group_item,
11634bbdec80SJiri Pirko 			  enum devlink_command cmd)
11644bbdec80SJiri Pirko {
11654bbdec80SJiri Pirko 	struct sk_buff *msg;
11664bbdec80SJiri Pirko 	int err;
11674bbdec80SJiri Pirko 
11684bbdec80SJiri Pirko 	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
11694bbdec80SJiri Pirko 		     cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
1170337ad364SJiri Pirko 
1171cddbff47SJiri Pirko 	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
11724bbdec80SJiri Pirko 		return;
11734bbdec80SJiri Pirko 
11744bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11754bbdec80SJiri Pirko 	if (!msg)
11764bbdec80SJiri Pirko 		return;
11774bbdec80SJiri Pirko 
11784bbdec80SJiri Pirko 	err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
11794bbdec80SJiri Pirko 					 0);
11804bbdec80SJiri Pirko 	if (err) {
11814bbdec80SJiri Pirko 		nlmsg_free(msg);
11824bbdec80SJiri Pirko 		return;
11834bbdec80SJiri Pirko 	}
11844bbdec80SJiri Pirko 
11855648de0bSJiri Pirko 	devlink_nl_notify_send(devlink, msg);
11864bbdec80SJiri Pirko }
11874bbdec80SJiri Pirko 
devlink_trap_groups_notify_register(struct devlink * devlink)11884bbdec80SJiri Pirko void devlink_trap_groups_notify_register(struct devlink *devlink)
11894bbdec80SJiri Pirko {
11904bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
11914bbdec80SJiri Pirko 
11924bbdec80SJiri Pirko 	list_for_each_entry(group_item, &devlink->trap_group_list, list)
11934bbdec80SJiri Pirko 		devlink_trap_group_notify(devlink, group_item,
11944bbdec80SJiri Pirko 					  DEVLINK_CMD_TRAP_GROUP_NEW);
11954bbdec80SJiri Pirko }
11964bbdec80SJiri Pirko 
devlink_trap_groups_notify_unregister(struct devlink * devlink)11974bbdec80SJiri Pirko void devlink_trap_groups_notify_unregister(struct devlink *devlink)
11984bbdec80SJiri Pirko {
11994bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
12004bbdec80SJiri Pirko 
12014bbdec80SJiri Pirko 	list_for_each_entry_reverse(group_item, &devlink->trap_group_list, list)
12024bbdec80SJiri Pirko 		devlink_trap_group_notify(devlink, group_item,
12034bbdec80SJiri Pirko 					  DEVLINK_CMD_TRAP_GROUP_DEL);
12044bbdec80SJiri Pirko }
12054bbdec80SJiri Pirko 
12064bbdec80SJiri Pirko static int
devlink_trap_item_group_link(struct devlink * devlink,struct devlink_trap_item * trap_item)12074bbdec80SJiri Pirko devlink_trap_item_group_link(struct devlink *devlink,
12084bbdec80SJiri Pirko 			     struct devlink_trap_item *trap_item)
12094bbdec80SJiri Pirko {
12104bbdec80SJiri Pirko 	u16 group_id = trap_item->trap->init_group_id;
12114bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
12124bbdec80SJiri Pirko 
12134bbdec80SJiri Pirko 	group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
12144bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!group_item))
12154bbdec80SJiri Pirko 		return -EINVAL;
12164bbdec80SJiri Pirko 
12174bbdec80SJiri Pirko 	trap_item->group_item = group_item;
12184bbdec80SJiri Pirko 
12194bbdec80SJiri Pirko 	return 0;
12204bbdec80SJiri Pirko }
12214bbdec80SJiri Pirko 
devlink_trap_notify(struct devlink * devlink,const struct devlink_trap_item * trap_item,enum devlink_command cmd)12224bbdec80SJiri Pirko static void devlink_trap_notify(struct devlink *devlink,
12234bbdec80SJiri Pirko 				const struct devlink_trap_item *trap_item,
12244bbdec80SJiri Pirko 				enum devlink_command cmd)
12254bbdec80SJiri Pirko {
12264bbdec80SJiri Pirko 	struct sk_buff *msg;
12274bbdec80SJiri Pirko 	int err;
12284bbdec80SJiri Pirko 
12294bbdec80SJiri Pirko 	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
12304bbdec80SJiri Pirko 		     cmd != DEVLINK_CMD_TRAP_DEL);
1231337ad364SJiri Pirko 
1232cddbff47SJiri Pirko 	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
12334bbdec80SJiri Pirko 		return;
12344bbdec80SJiri Pirko 
12354bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
12364bbdec80SJiri Pirko 	if (!msg)
12374bbdec80SJiri Pirko 		return;
12384bbdec80SJiri Pirko 
12394bbdec80SJiri Pirko 	err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
12404bbdec80SJiri Pirko 	if (err) {
12414bbdec80SJiri Pirko 		nlmsg_free(msg);
12424bbdec80SJiri Pirko 		return;
12434bbdec80SJiri Pirko 	}
12444bbdec80SJiri Pirko 
12455648de0bSJiri Pirko 	devlink_nl_notify_send(devlink, msg);
12464bbdec80SJiri Pirko }
12474bbdec80SJiri Pirko 
devlink_traps_notify_register(struct devlink * devlink)12484bbdec80SJiri Pirko void devlink_traps_notify_register(struct devlink *devlink)
12494bbdec80SJiri Pirko {
12504bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
12514bbdec80SJiri Pirko 
12524bbdec80SJiri Pirko 	list_for_each_entry(trap_item, &devlink->trap_list, list)
12534bbdec80SJiri Pirko 		devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
12544bbdec80SJiri Pirko }
12554bbdec80SJiri Pirko 
devlink_traps_notify_unregister(struct devlink * devlink)12564bbdec80SJiri Pirko void devlink_traps_notify_unregister(struct devlink *devlink)
12574bbdec80SJiri Pirko {
12584bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
12594bbdec80SJiri Pirko 
12604bbdec80SJiri Pirko 	list_for_each_entry_reverse(trap_item, &devlink->trap_list, list)
12614bbdec80SJiri Pirko 		devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
12624bbdec80SJiri Pirko }
12634bbdec80SJiri Pirko 
12644bbdec80SJiri Pirko static int
devlink_trap_register(struct devlink * devlink,const struct devlink_trap * trap,void * priv)12654bbdec80SJiri Pirko devlink_trap_register(struct devlink *devlink,
12664bbdec80SJiri Pirko 		      const struct devlink_trap *trap, void *priv)
12674bbdec80SJiri Pirko {
12684bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
12694bbdec80SJiri Pirko 	int err;
12704bbdec80SJiri Pirko 
12714bbdec80SJiri Pirko 	if (devlink_trap_item_lookup(devlink, trap->name))
12724bbdec80SJiri Pirko 		return -EEXIST;
12734bbdec80SJiri Pirko 
12744bbdec80SJiri Pirko 	trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
12754bbdec80SJiri Pirko 	if (!trap_item)
12764bbdec80SJiri Pirko 		return -ENOMEM;
12774bbdec80SJiri Pirko 
12784bbdec80SJiri Pirko 	trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
12794bbdec80SJiri Pirko 	if (!trap_item->stats) {
12804bbdec80SJiri Pirko 		err = -ENOMEM;
12814bbdec80SJiri Pirko 		goto err_stats_alloc;
12824bbdec80SJiri Pirko 	}
12834bbdec80SJiri Pirko 
12844bbdec80SJiri Pirko 	trap_item->trap = trap;
12854bbdec80SJiri Pirko 	trap_item->action = trap->init_action;
12864bbdec80SJiri Pirko 	trap_item->priv = priv;
12874bbdec80SJiri Pirko 
12884bbdec80SJiri Pirko 	err = devlink_trap_item_group_link(devlink, trap_item);
12894bbdec80SJiri Pirko 	if (err)
12904bbdec80SJiri Pirko 		goto err_group_link;
12914bbdec80SJiri Pirko 
12924bbdec80SJiri Pirko 	err = devlink->ops->trap_init(devlink, trap, trap_item);
12934bbdec80SJiri Pirko 	if (err)
12944bbdec80SJiri Pirko 		goto err_trap_init;
12954bbdec80SJiri Pirko 
12964bbdec80SJiri Pirko 	list_add_tail(&trap_item->list, &devlink->trap_list);
12974bbdec80SJiri Pirko 	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
12984bbdec80SJiri Pirko 
12994bbdec80SJiri Pirko 	return 0;
13004bbdec80SJiri Pirko 
13014bbdec80SJiri Pirko err_trap_init:
13024bbdec80SJiri Pirko err_group_link:
13034bbdec80SJiri Pirko 	free_percpu(trap_item->stats);
13044bbdec80SJiri Pirko err_stats_alloc:
13054bbdec80SJiri Pirko 	kfree(trap_item);
13064bbdec80SJiri Pirko 	return err;
13074bbdec80SJiri Pirko }
13084bbdec80SJiri Pirko 
devlink_trap_unregister(struct devlink * devlink,const struct devlink_trap * trap)13094bbdec80SJiri Pirko static void devlink_trap_unregister(struct devlink *devlink,
13104bbdec80SJiri Pirko 				    const struct devlink_trap *trap)
13114bbdec80SJiri Pirko {
13124bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
13134bbdec80SJiri Pirko 
13144bbdec80SJiri Pirko 	trap_item = devlink_trap_item_lookup(devlink, trap->name);
13154bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!trap_item))
13164bbdec80SJiri Pirko 		return;
13174bbdec80SJiri Pirko 
13184bbdec80SJiri Pirko 	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
13194bbdec80SJiri Pirko 	list_del(&trap_item->list);
13204bbdec80SJiri Pirko 	if (devlink->ops->trap_fini)
13214bbdec80SJiri Pirko 		devlink->ops->trap_fini(devlink, trap, trap_item);
13224bbdec80SJiri Pirko 	free_percpu(trap_item->stats);
13234bbdec80SJiri Pirko 	kfree(trap_item);
13244bbdec80SJiri Pirko }
13254bbdec80SJiri Pirko 
devlink_trap_disable(struct devlink * devlink,const struct devlink_trap * trap)13264bbdec80SJiri Pirko static void devlink_trap_disable(struct devlink *devlink,
13274bbdec80SJiri Pirko 				 const struct devlink_trap *trap)
13284bbdec80SJiri Pirko {
13294bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item;
13304bbdec80SJiri Pirko 
13314bbdec80SJiri Pirko 	trap_item = devlink_trap_item_lookup(devlink, trap->name);
13324bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!trap_item))
13334bbdec80SJiri Pirko 		return;
13344bbdec80SJiri Pirko 
13354bbdec80SJiri Pirko 	devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
13364bbdec80SJiri Pirko 				      NULL);
13374bbdec80SJiri Pirko 	trap_item->action = DEVLINK_TRAP_ACTION_DROP;
13384bbdec80SJiri Pirko }
13394bbdec80SJiri Pirko 
13404bbdec80SJiri Pirko /**
13414bbdec80SJiri Pirko  * devl_traps_register - Register packet traps with devlink.
13424bbdec80SJiri Pirko  * @devlink: devlink.
13434bbdec80SJiri Pirko  * @traps: Packet traps.
13444bbdec80SJiri Pirko  * @traps_count: Count of provided packet traps.
13454bbdec80SJiri Pirko  * @priv: Driver private information.
13464bbdec80SJiri Pirko  *
13474bbdec80SJiri Pirko  * Return: Non-zero value on failure.
13484bbdec80SJiri Pirko  */
devl_traps_register(struct devlink * devlink,const struct devlink_trap * traps,size_t traps_count,void * priv)13494bbdec80SJiri Pirko int devl_traps_register(struct devlink *devlink,
13504bbdec80SJiri Pirko 			const struct devlink_trap *traps,
13514bbdec80SJiri Pirko 			size_t traps_count, void *priv)
13524bbdec80SJiri Pirko {
13534bbdec80SJiri Pirko 	int i, err;
13544bbdec80SJiri Pirko 
13554bbdec80SJiri Pirko 	if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
13564bbdec80SJiri Pirko 		return -EINVAL;
13574bbdec80SJiri Pirko 
13584bbdec80SJiri Pirko 	devl_assert_locked(devlink);
13594bbdec80SJiri Pirko 	for (i = 0; i < traps_count; i++) {
13604bbdec80SJiri Pirko 		const struct devlink_trap *trap = &traps[i];
13614bbdec80SJiri Pirko 
13624bbdec80SJiri Pirko 		err = devlink_trap_verify(trap);
13634bbdec80SJiri Pirko 		if (err)
13644bbdec80SJiri Pirko 			goto err_trap_verify;
13654bbdec80SJiri Pirko 
13664bbdec80SJiri Pirko 		err = devlink_trap_register(devlink, trap, priv);
13674bbdec80SJiri Pirko 		if (err)
13684bbdec80SJiri Pirko 			goto err_trap_register;
13694bbdec80SJiri Pirko 	}
13704bbdec80SJiri Pirko 
13714bbdec80SJiri Pirko 	return 0;
13724bbdec80SJiri Pirko 
13734bbdec80SJiri Pirko err_trap_register:
13744bbdec80SJiri Pirko err_trap_verify:
13754bbdec80SJiri Pirko 	for (i--; i >= 0; i--)
13764bbdec80SJiri Pirko 		devlink_trap_unregister(devlink, &traps[i]);
13774bbdec80SJiri Pirko 	return err;
13784bbdec80SJiri Pirko }
13794bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_traps_register);
13804bbdec80SJiri Pirko 
13814bbdec80SJiri Pirko /**
13824bbdec80SJiri Pirko  * devlink_traps_register - Register packet traps with devlink.
13834bbdec80SJiri Pirko  * @devlink: devlink.
13844bbdec80SJiri Pirko  * @traps: Packet traps.
13854bbdec80SJiri Pirko  * @traps_count: Count of provided packet traps.
13864bbdec80SJiri Pirko  * @priv: Driver private information.
13874bbdec80SJiri Pirko  *
13884bbdec80SJiri Pirko  * Context: Takes and release devlink->lock <mutex>.
13894bbdec80SJiri Pirko  *
13904bbdec80SJiri Pirko  * Return: Non-zero value on failure.
13914bbdec80SJiri Pirko  */
devlink_traps_register(struct devlink * devlink,const struct devlink_trap * traps,size_t traps_count,void * priv)13924bbdec80SJiri Pirko int devlink_traps_register(struct devlink *devlink,
13934bbdec80SJiri Pirko 			   const struct devlink_trap *traps,
13944bbdec80SJiri Pirko 			   size_t traps_count, void *priv)
13954bbdec80SJiri Pirko {
13964bbdec80SJiri Pirko 	int err;
13974bbdec80SJiri Pirko 
13984bbdec80SJiri Pirko 	devl_lock(devlink);
13994bbdec80SJiri Pirko 	err = devl_traps_register(devlink, traps, traps_count, priv);
14004bbdec80SJiri Pirko 	devl_unlock(devlink);
14014bbdec80SJiri Pirko 	return err;
14024bbdec80SJiri Pirko }
14034bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_traps_register);
14044bbdec80SJiri Pirko 
14054bbdec80SJiri Pirko /**
14064bbdec80SJiri Pirko  * devl_traps_unregister - Unregister packet traps from devlink.
14074bbdec80SJiri Pirko  * @devlink: devlink.
14084bbdec80SJiri Pirko  * @traps: Packet traps.
14094bbdec80SJiri Pirko  * @traps_count: Count of provided packet traps.
14104bbdec80SJiri Pirko  */
devl_traps_unregister(struct devlink * devlink,const struct devlink_trap * traps,size_t traps_count)14114bbdec80SJiri Pirko void devl_traps_unregister(struct devlink *devlink,
14124bbdec80SJiri Pirko 			   const struct devlink_trap *traps,
14134bbdec80SJiri Pirko 			   size_t traps_count)
14144bbdec80SJiri Pirko {
14154bbdec80SJiri Pirko 	int i;
14164bbdec80SJiri Pirko 
14174bbdec80SJiri Pirko 	devl_assert_locked(devlink);
14184bbdec80SJiri Pirko 	/* Make sure we do not have any packets in-flight while unregistering
14194bbdec80SJiri Pirko 	 * traps by disabling all of them and waiting for a grace period.
14204bbdec80SJiri Pirko 	 */
14214bbdec80SJiri Pirko 	for (i = traps_count - 1; i >= 0; i--)
14224bbdec80SJiri Pirko 		devlink_trap_disable(devlink, &traps[i]);
14234bbdec80SJiri Pirko 	synchronize_rcu();
14244bbdec80SJiri Pirko 	for (i = traps_count - 1; i >= 0; i--)
14254bbdec80SJiri Pirko 		devlink_trap_unregister(devlink, &traps[i]);
14264bbdec80SJiri Pirko }
14274bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_traps_unregister);
14284bbdec80SJiri Pirko 
14294bbdec80SJiri Pirko /**
14304bbdec80SJiri Pirko  * devlink_traps_unregister - Unregister packet traps from devlink.
14314bbdec80SJiri Pirko  * @devlink: devlink.
14324bbdec80SJiri Pirko  * @traps: Packet traps.
14334bbdec80SJiri Pirko  * @traps_count: Count of provided packet traps.
14344bbdec80SJiri Pirko  *
14354bbdec80SJiri Pirko  * Context: Takes and release devlink->lock <mutex>.
14364bbdec80SJiri Pirko  */
devlink_traps_unregister(struct devlink * devlink,const struct devlink_trap * traps,size_t traps_count)14374bbdec80SJiri Pirko void devlink_traps_unregister(struct devlink *devlink,
14384bbdec80SJiri Pirko 			      const struct devlink_trap *traps,
14394bbdec80SJiri Pirko 			      size_t traps_count)
14404bbdec80SJiri Pirko {
14414bbdec80SJiri Pirko 	devl_lock(devlink);
14424bbdec80SJiri Pirko 	devl_traps_unregister(devlink, traps, traps_count);
14434bbdec80SJiri Pirko 	devl_unlock(devlink);
14444bbdec80SJiri Pirko }
14454bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_traps_unregister);
14464bbdec80SJiri Pirko 
14474bbdec80SJiri Pirko static void
devlink_trap_stats_update(struct devlink_stats __percpu * trap_stats,size_t skb_len)14484bbdec80SJiri Pirko devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
14494bbdec80SJiri Pirko 			  size_t skb_len)
14504bbdec80SJiri Pirko {
14514bbdec80SJiri Pirko 	struct devlink_stats *stats;
14524bbdec80SJiri Pirko 
14534bbdec80SJiri Pirko 	stats = this_cpu_ptr(trap_stats);
14544bbdec80SJiri Pirko 	u64_stats_update_begin(&stats->syncp);
14554bbdec80SJiri Pirko 	u64_stats_add(&stats->rx_bytes, skb_len);
14564bbdec80SJiri Pirko 	u64_stats_inc(&stats->rx_packets);
14574bbdec80SJiri Pirko 	u64_stats_update_end(&stats->syncp);
14584bbdec80SJiri Pirko }
14594bbdec80SJiri Pirko 
14604bbdec80SJiri Pirko static void
devlink_trap_report_metadata_set(struct devlink_trap_metadata * metadata,const struct devlink_trap_item * trap_item,struct devlink_port * in_devlink_port,const struct flow_action_cookie * fa_cookie)14614bbdec80SJiri Pirko devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
14624bbdec80SJiri Pirko 				 const struct devlink_trap_item *trap_item,
14634bbdec80SJiri Pirko 				 struct devlink_port *in_devlink_port,
14644bbdec80SJiri Pirko 				 const struct flow_action_cookie *fa_cookie)
14654bbdec80SJiri Pirko {
14664bbdec80SJiri Pirko 	metadata->trap_name = trap_item->trap->name;
14674bbdec80SJiri Pirko 	metadata->trap_group_name = trap_item->group_item->group->name;
14684bbdec80SJiri Pirko 	metadata->fa_cookie = fa_cookie;
14694bbdec80SJiri Pirko 	metadata->trap_type = trap_item->trap->type;
14704bbdec80SJiri Pirko 
14714bbdec80SJiri Pirko 	spin_lock(&in_devlink_port->type_lock);
14724bbdec80SJiri Pirko 	if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
14734bbdec80SJiri Pirko 		metadata->input_dev = in_devlink_port->type_eth.netdev;
14744bbdec80SJiri Pirko 	spin_unlock(&in_devlink_port->type_lock);
14754bbdec80SJiri Pirko }
14764bbdec80SJiri Pirko 
14774bbdec80SJiri Pirko /**
14784bbdec80SJiri Pirko  * devlink_trap_report - Report trapped packet to drop monitor.
14794bbdec80SJiri Pirko  * @devlink: devlink.
14804bbdec80SJiri Pirko  * @skb: Trapped packet.
14814bbdec80SJiri Pirko  * @trap_ctx: Trap context.
14824bbdec80SJiri Pirko  * @in_devlink_port: Input devlink port.
14834bbdec80SJiri Pirko  * @fa_cookie: Flow action cookie. Could be NULL.
14844bbdec80SJiri Pirko  */
devlink_trap_report(struct devlink * devlink,struct sk_buff * skb,void * trap_ctx,struct devlink_port * in_devlink_port,const struct flow_action_cookie * fa_cookie)14854bbdec80SJiri Pirko void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
14864bbdec80SJiri Pirko 			 void *trap_ctx, struct devlink_port *in_devlink_port,
14874bbdec80SJiri Pirko 			 const struct flow_action_cookie *fa_cookie)
14884bbdec80SJiri Pirko 
14894bbdec80SJiri Pirko {
14904bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item = trap_ctx;
14914bbdec80SJiri Pirko 
14924bbdec80SJiri Pirko 	devlink_trap_stats_update(trap_item->stats, skb->len);
14934bbdec80SJiri Pirko 	devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
14944bbdec80SJiri Pirko 
14954bbdec80SJiri Pirko 	if (tracepoint_enabled(devlink_trap_report)) {
14964bbdec80SJiri Pirko 		struct devlink_trap_metadata metadata = {};
14974bbdec80SJiri Pirko 
14984bbdec80SJiri Pirko 		devlink_trap_report_metadata_set(&metadata, trap_item,
14994bbdec80SJiri Pirko 						 in_devlink_port, fa_cookie);
15004bbdec80SJiri Pirko 		trace_devlink_trap_report(devlink, skb, &metadata);
15014bbdec80SJiri Pirko 	}
15024bbdec80SJiri Pirko }
15034bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_trap_report);
15044bbdec80SJiri Pirko 
15054bbdec80SJiri Pirko /**
15064bbdec80SJiri Pirko  * devlink_trap_ctx_priv - Trap context to driver private information.
15074bbdec80SJiri Pirko  * @trap_ctx: Trap context.
15084bbdec80SJiri Pirko  *
15094bbdec80SJiri Pirko  * Return: Driver private information passed during registration.
15104bbdec80SJiri Pirko  */
devlink_trap_ctx_priv(void * trap_ctx)15114bbdec80SJiri Pirko void *devlink_trap_ctx_priv(void *trap_ctx)
15124bbdec80SJiri Pirko {
15134bbdec80SJiri Pirko 	struct devlink_trap_item *trap_item = trap_ctx;
15144bbdec80SJiri Pirko 
15154bbdec80SJiri Pirko 	return trap_item->priv;
15164bbdec80SJiri Pirko }
15174bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
15184bbdec80SJiri Pirko 
15194bbdec80SJiri Pirko static int
devlink_trap_group_item_policer_link(struct devlink * devlink,struct devlink_trap_group_item * group_item)15204bbdec80SJiri Pirko devlink_trap_group_item_policer_link(struct devlink *devlink,
15214bbdec80SJiri Pirko 				     struct devlink_trap_group_item *group_item)
15224bbdec80SJiri Pirko {
15234bbdec80SJiri Pirko 	u32 policer_id = group_item->group->init_policer_id;
15244bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
15254bbdec80SJiri Pirko 
15264bbdec80SJiri Pirko 	if (policer_id == 0)
15274bbdec80SJiri Pirko 		return 0;
15284bbdec80SJiri Pirko 
15294bbdec80SJiri Pirko 	policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
15304bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!policer_item))
15314bbdec80SJiri Pirko 		return -EINVAL;
15324bbdec80SJiri Pirko 
15334bbdec80SJiri Pirko 	group_item->policer_item = policer_item;
15344bbdec80SJiri Pirko 
15354bbdec80SJiri Pirko 	return 0;
15364bbdec80SJiri Pirko }
15374bbdec80SJiri Pirko 
15384bbdec80SJiri Pirko static int
devlink_trap_group_register(struct devlink * devlink,const struct devlink_trap_group * group)15394bbdec80SJiri Pirko devlink_trap_group_register(struct devlink *devlink,
15404bbdec80SJiri Pirko 			    const struct devlink_trap_group *group)
15414bbdec80SJiri Pirko {
15424bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
15434bbdec80SJiri Pirko 	int err;
15444bbdec80SJiri Pirko 
15454bbdec80SJiri Pirko 	if (devlink_trap_group_item_lookup(devlink, group->name))
15464bbdec80SJiri Pirko 		return -EEXIST;
15474bbdec80SJiri Pirko 
15484bbdec80SJiri Pirko 	group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
15494bbdec80SJiri Pirko 	if (!group_item)
15504bbdec80SJiri Pirko 		return -ENOMEM;
15514bbdec80SJiri Pirko 
15524bbdec80SJiri Pirko 	group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
15534bbdec80SJiri Pirko 	if (!group_item->stats) {
15544bbdec80SJiri Pirko 		err = -ENOMEM;
15554bbdec80SJiri Pirko 		goto err_stats_alloc;
15564bbdec80SJiri Pirko 	}
15574bbdec80SJiri Pirko 
15584bbdec80SJiri Pirko 	group_item->group = group;
15594bbdec80SJiri Pirko 
15604bbdec80SJiri Pirko 	err = devlink_trap_group_item_policer_link(devlink, group_item);
15614bbdec80SJiri Pirko 	if (err)
15624bbdec80SJiri Pirko 		goto err_policer_link;
15634bbdec80SJiri Pirko 
15644bbdec80SJiri Pirko 	if (devlink->ops->trap_group_init) {
15654bbdec80SJiri Pirko 		err = devlink->ops->trap_group_init(devlink, group);
15664bbdec80SJiri Pirko 		if (err)
15674bbdec80SJiri Pirko 			goto err_group_init;
15684bbdec80SJiri Pirko 	}
15694bbdec80SJiri Pirko 
15704bbdec80SJiri Pirko 	list_add_tail(&group_item->list, &devlink->trap_group_list);
15714bbdec80SJiri Pirko 	devlink_trap_group_notify(devlink, group_item,
15724bbdec80SJiri Pirko 				  DEVLINK_CMD_TRAP_GROUP_NEW);
15734bbdec80SJiri Pirko 
15744bbdec80SJiri Pirko 	return 0;
15754bbdec80SJiri Pirko 
15764bbdec80SJiri Pirko err_group_init:
15774bbdec80SJiri Pirko err_policer_link:
15784bbdec80SJiri Pirko 	free_percpu(group_item->stats);
15794bbdec80SJiri Pirko err_stats_alloc:
15804bbdec80SJiri Pirko 	kfree(group_item);
15814bbdec80SJiri Pirko 	return err;
15824bbdec80SJiri Pirko }
15834bbdec80SJiri Pirko 
15844bbdec80SJiri Pirko static void
devlink_trap_group_unregister(struct devlink * devlink,const struct devlink_trap_group * group)15854bbdec80SJiri Pirko devlink_trap_group_unregister(struct devlink *devlink,
15864bbdec80SJiri Pirko 			      const struct devlink_trap_group *group)
15874bbdec80SJiri Pirko {
15884bbdec80SJiri Pirko 	struct devlink_trap_group_item *group_item;
15894bbdec80SJiri Pirko 
15904bbdec80SJiri Pirko 	group_item = devlink_trap_group_item_lookup(devlink, group->name);
15914bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!group_item))
15924bbdec80SJiri Pirko 		return;
15934bbdec80SJiri Pirko 
15944bbdec80SJiri Pirko 	devlink_trap_group_notify(devlink, group_item,
15954bbdec80SJiri Pirko 				  DEVLINK_CMD_TRAP_GROUP_DEL);
15964bbdec80SJiri Pirko 	list_del(&group_item->list);
15974bbdec80SJiri Pirko 	free_percpu(group_item->stats);
15984bbdec80SJiri Pirko 	kfree(group_item);
15994bbdec80SJiri Pirko }
16004bbdec80SJiri Pirko 
16014bbdec80SJiri Pirko /**
16024bbdec80SJiri Pirko  * devl_trap_groups_register - Register packet trap groups with devlink.
16034bbdec80SJiri Pirko  * @devlink: devlink.
16044bbdec80SJiri Pirko  * @groups: Packet trap groups.
16054bbdec80SJiri Pirko  * @groups_count: Count of provided packet trap groups.
16064bbdec80SJiri Pirko  *
16074bbdec80SJiri Pirko  * Return: Non-zero value on failure.
16084bbdec80SJiri Pirko  */
devl_trap_groups_register(struct devlink * devlink,const struct devlink_trap_group * groups,size_t groups_count)16094bbdec80SJiri Pirko int devl_trap_groups_register(struct devlink *devlink,
16104bbdec80SJiri Pirko 			      const struct devlink_trap_group *groups,
16114bbdec80SJiri Pirko 			      size_t groups_count)
16124bbdec80SJiri Pirko {
16134bbdec80SJiri Pirko 	int i, err;
16144bbdec80SJiri Pirko 
16154bbdec80SJiri Pirko 	devl_assert_locked(devlink);
16164bbdec80SJiri Pirko 	for (i = 0; i < groups_count; i++) {
16174bbdec80SJiri Pirko 		const struct devlink_trap_group *group = &groups[i];
16184bbdec80SJiri Pirko 
16194bbdec80SJiri Pirko 		err = devlink_trap_group_verify(group);
16204bbdec80SJiri Pirko 		if (err)
16214bbdec80SJiri Pirko 			goto err_trap_group_verify;
16224bbdec80SJiri Pirko 
16234bbdec80SJiri Pirko 		err = devlink_trap_group_register(devlink, group);
16244bbdec80SJiri Pirko 		if (err)
16254bbdec80SJiri Pirko 			goto err_trap_group_register;
16264bbdec80SJiri Pirko 	}
16274bbdec80SJiri Pirko 
16284bbdec80SJiri Pirko 	return 0;
16294bbdec80SJiri Pirko 
16304bbdec80SJiri Pirko err_trap_group_register:
16314bbdec80SJiri Pirko err_trap_group_verify:
16324bbdec80SJiri Pirko 	for (i--; i >= 0; i--)
16334bbdec80SJiri Pirko 		devlink_trap_group_unregister(devlink, &groups[i]);
16344bbdec80SJiri Pirko 	return err;
16354bbdec80SJiri Pirko }
16364bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_trap_groups_register);
16374bbdec80SJiri Pirko 
16384bbdec80SJiri Pirko /**
16394bbdec80SJiri Pirko  * devlink_trap_groups_register - Register packet trap groups with devlink.
16404bbdec80SJiri Pirko  * @devlink: devlink.
16414bbdec80SJiri Pirko  * @groups: Packet trap groups.
16424bbdec80SJiri Pirko  * @groups_count: Count of provided packet trap groups.
16434bbdec80SJiri Pirko  *
16444bbdec80SJiri Pirko  * Context: Takes and release devlink->lock <mutex>.
16454bbdec80SJiri Pirko  *
16464bbdec80SJiri Pirko  * Return: Non-zero value on failure.
16474bbdec80SJiri Pirko  */
devlink_trap_groups_register(struct devlink * devlink,const struct devlink_trap_group * groups,size_t groups_count)16484bbdec80SJiri Pirko int devlink_trap_groups_register(struct devlink *devlink,
16494bbdec80SJiri Pirko 				 const struct devlink_trap_group *groups,
16504bbdec80SJiri Pirko 				 size_t groups_count)
16514bbdec80SJiri Pirko {
16524bbdec80SJiri Pirko 	int err;
16534bbdec80SJiri Pirko 
16544bbdec80SJiri Pirko 	devl_lock(devlink);
16554bbdec80SJiri Pirko 	err = devl_trap_groups_register(devlink, groups, groups_count);
16564bbdec80SJiri Pirko 	devl_unlock(devlink);
16574bbdec80SJiri Pirko 	return err;
16584bbdec80SJiri Pirko }
16594bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
16604bbdec80SJiri Pirko 
16614bbdec80SJiri Pirko /**
16624bbdec80SJiri Pirko  * devl_trap_groups_unregister - Unregister packet trap groups from devlink.
16634bbdec80SJiri Pirko  * @devlink: devlink.
16644bbdec80SJiri Pirko  * @groups: Packet trap groups.
16654bbdec80SJiri Pirko  * @groups_count: Count of provided packet trap groups.
16664bbdec80SJiri Pirko  */
devl_trap_groups_unregister(struct devlink * devlink,const struct devlink_trap_group * groups,size_t groups_count)16674bbdec80SJiri Pirko void devl_trap_groups_unregister(struct devlink *devlink,
16684bbdec80SJiri Pirko 				 const struct devlink_trap_group *groups,
16694bbdec80SJiri Pirko 				 size_t groups_count)
16704bbdec80SJiri Pirko {
16714bbdec80SJiri Pirko 	int i;
16724bbdec80SJiri Pirko 
16734bbdec80SJiri Pirko 	devl_assert_locked(devlink);
16744bbdec80SJiri Pirko 	for (i = groups_count - 1; i >= 0; i--)
16754bbdec80SJiri Pirko 		devlink_trap_group_unregister(devlink, &groups[i]);
16764bbdec80SJiri Pirko }
16774bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_trap_groups_unregister);
16784bbdec80SJiri Pirko 
16794bbdec80SJiri Pirko /**
16804bbdec80SJiri Pirko  * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
16814bbdec80SJiri Pirko  * @devlink: devlink.
16824bbdec80SJiri Pirko  * @groups: Packet trap groups.
16834bbdec80SJiri Pirko  * @groups_count: Count of provided packet trap groups.
16844bbdec80SJiri Pirko  *
16854bbdec80SJiri Pirko  * Context: Takes and release devlink->lock <mutex>.
16864bbdec80SJiri Pirko  */
devlink_trap_groups_unregister(struct devlink * devlink,const struct devlink_trap_group * groups,size_t groups_count)16874bbdec80SJiri Pirko void devlink_trap_groups_unregister(struct devlink *devlink,
16884bbdec80SJiri Pirko 				    const struct devlink_trap_group *groups,
16894bbdec80SJiri Pirko 				    size_t groups_count)
16904bbdec80SJiri Pirko {
16914bbdec80SJiri Pirko 	devl_lock(devlink);
16924bbdec80SJiri Pirko 	devl_trap_groups_unregister(devlink, groups, groups_count);
16934bbdec80SJiri Pirko 	devl_unlock(devlink);
16944bbdec80SJiri Pirko }
16954bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
16964bbdec80SJiri Pirko 
16974bbdec80SJiri Pirko static void
devlink_trap_policer_notify(struct devlink * devlink,const struct devlink_trap_policer_item * policer_item,enum devlink_command cmd)16984bbdec80SJiri Pirko devlink_trap_policer_notify(struct devlink *devlink,
16994bbdec80SJiri Pirko 			    const struct devlink_trap_policer_item *policer_item,
17004bbdec80SJiri Pirko 			    enum devlink_command cmd)
17014bbdec80SJiri Pirko {
17024bbdec80SJiri Pirko 	struct sk_buff *msg;
17034bbdec80SJiri Pirko 	int err;
17044bbdec80SJiri Pirko 
17054bbdec80SJiri Pirko 	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
17064bbdec80SJiri Pirko 		     cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
1707337ad364SJiri Pirko 
1708cddbff47SJiri Pirko 	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
17094bbdec80SJiri Pirko 		return;
17104bbdec80SJiri Pirko 
17114bbdec80SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
17124bbdec80SJiri Pirko 	if (!msg)
17134bbdec80SJiri Pirko 		return;
17144bbdec80SJiri Pirko 
17154bbdec80SJiri Pirko 	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
17164bbdec80SJiri Pirko 					   0, 0);
17174bbdec80SJiri Pirko 	if (err) {
17184bbdec80SJiri Pirko 		nlmsg_free(msg);
17194bbdec80SJiri Pirko 		return;
17204bbdec80SJiri Pirko 	}
17214bbdec80SJiri Pirko 
17225648de0bSJiri Pirko 	devlink_nl_notify_send(devlink, msg);
17234bbdec80SJiri Pirko }
17244bbdec80SJiri Pirko 
devlink_trap_policers_notify_register(struct devlink * devlink)17254bbdec80SJiri Pirko void devlink_trap_policers_notify_register(struct devlink *devlink)
17264bbdec80SJiri Pirko {
17274bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
17284bbdec80SJiri Pirko 
17294bbdec80SJiri Pirko 	list_for_each_entry(policer_item, &devlink->trap_policer_list, list)
17304bbdec80SJiri Pirko 		devlink_trap_policer_notify(devlink, policer_item,
17314bbdec80SJiri Pirko 					    DEVLINK_CMD_TRAP_POLICER_NEW);
17324bbdec80SJiri Pirko }
17334bbdec80SJiri Pirko 
devlink_trap_policers_notify_unregister(struct devlink * devlink)17344bbdec80SJiri Pirko void devlink_trap_policers_notify_unregister(struct devlink *devlink)
17354bbdec80SJiri Pirko {
17364bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
17374bbdec80SJiri Pirko 
17384bbdec80SJiri Pirko 	list_for_each_entry_reverse(policer_item, &devlink->trap_policer_list,
17394bbdec80SJiri Pirko 				    list)
17404bbdec80SJiri Pirko 		devlink_trap_policer_notify(devlink, policer_item,
17414bbdec80SJiri Pirko 					    DEVLINK_CMD_TRAP_POLICER_DEL);
17424bbdec80SJiri Pirko }
17434bbdec80SJiri Pirko 
17444bbdec80SJiri Pirko static int
devlink_trap_policer_register(struct devlink * devlink,const struct devlink_trap_policer * policer)17454bbdec80SJiri Pirko devlink_trap_policer_register(struct devlink *devlink,
17464bbdec80SJiri Pirko 			      const struct devlink_trap_policer *policer)
17474bbdec80SJiri Pirko {
17484bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
17494bbdec80SJiri Pirko 	int err;
17504bbdec80SJiri Pirko 
17514bbdec80SJiri Pirko 	if (devlink_trap_policer_item_lookup(devlink, policer->id))
17524bbdec80SJiri Pirko 		return -EEXIST;
17534bbdec80SJiri Pirko 
17544bbdec80SJiri Pirko 	policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
17554bbdec80SJiri Pirko 	if (!policer_item)
17564bbdec80SJiri Pirko 		return -ENOMEM;
17574bbdec80SJiri Pirko 
17584bbdec80SJiri Pirko 	policer_item->policer = policer;
17594bbdec80SJiri Pirko 	policer_item->rate = policer->init_rate;
17604bbdec80SJiri Pirko 	policer_item->burst = policer->init_burst;
17614bbdec80SJiri Pirko 
17624bbdec80SJiri Pirko 	if (devlink->ops->trap_policer_init) {
17634bbdec80SJiri Pirko 		err = devlink->ops->trap_policer_init(devlink, policer);
17644bbdec80SJiri Pirko 		if (err)
17654bbdec80SJiri Pirko 			goto err_policer_init;
17664bbdec80SJiri Pirko 	}
17674bbdec80SJiri Pirko 
17684bbdec80SJiri Pirko 	list_add_tail(&policer_item->list, &devlink->trap_policer_list);
17694bbdec80SJiri Pirko 	devlink_trap_policer_notify(devlink, policer_item,
17704bbdec80SJiri Pirko 				    DEVLINK_CMD_TRAP_POLICER_NEW);
17714bbdec80SJiri Pirko 
17724bbdec80SJiri Pirko 	return 0;
17734bbdec80SJiri Pirko 
17744bbdec80SJiri Pirko err_policer_init:
17754bbdec80SJiri Pirko 	kfree(policer_item);
17764bbdec80SJiri Pirko 	return err;
17774bbdec80SJiri Pirko }
17784bbdec80SJiri Pirko 
17794bbdec80SJiri Pirko static void
devlink_trap_policer_unregister(struct devlink * devlink,const struct devlink_trap_policer * policer)17804bbdec80SJiri Pirko devlink_trap_policer_unregister(struct devlink *devlink,
17814bbdec80SJiri Pirko 				const struct devlink_trap_policer *policer)
17824bbdec80SJiri Pirko {
17834bbdec80SJiri Pirko 	struct devlink_trap_policer_item *policer_item;
17844bbdec80SJiri Pirko 
17854bbdec80SJiri Pirko 	policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
17864bbdec80SJiri Pirko 	if (WARN_ON_ONCE(!policer_item))
17874bbdec80SJiri Pirko 		return;
17884bbdec80SJiri Pirko 
17894bbdec80SJiri Pirko 	devlink_trap_policer_notify(devlink, policer_item,
17904bbdec80SJiri Pirko 				    DEVLINK_CMD_TRAP_POLICER_DEL);
17914bbdec80SJiri Pirko 	list_del(&policer_item->list);
17924bbdec80SJiri Pirko 	if (devlink->ops->trap_policer_fini)
17934bbdec80SJiri Pirko 		devlink->ops->trap_policer_fini(devlink, policer);
17944bbdec80SJiri Pirko 	kfree(policer_item);
17954bbdec80SJiri Pirko }
17964bbdec80SJiri Pirko 
17974bbdec80SJiri Pirko /**
17984bbdec80SJiri Pirko  * devl_trap_policers_register - Register packet trap policers with devlink.
17994bbdec80SJiri Pirko  * @devlink: devlink.
18004bbdec80SJiri Pirko  * @policers: Packet trap policers.
18014bbdec80SJiri Pirko  * @policers_count: Count of provided packet trap policers.
18024bbdec80SJiri Pirko  *
18034bbdec80SJiri Pirko  * Return: Non-zero value on failure.
18044bbdec80SJiri Pirko  */
18054bbdec80SJiri Pirko int
devl_trap_policers_register(struct devlink * devlink,const struct devlink_trap_policer * policers,size_t policers_count)18064bbdec80SJiri Pirko devl_trap_policers_register(struct devlink *devlink,
18074bbdec80SJiri Pirko 			    const struct devlink_trap_policer *policers,
18084bbdec80SJiri Pirko 			    size_t policers_count)
18094bbdec80SJiri Pirko {
18104bbdec80SJiri Pirko 	int i, err;
18114bbdec80SJiri Pirko 
18124bbdec80SJiri Pirko 	devl_assert_locked(devlink);
18134bbdec80SJiri Pirko 	for (i = 0; i < policers_count; i++) {
18144bbdec80SJiri Pirko 		const struct devlink_trap_policer *policer = &policers[i];
18154bbdec80SJiri Pirko 
18164bbdec80SJiri Pirko 		if (WARN_ON(policer->id == 0 ||
18174bbdec80SJiri Pirko 			    policer->max_rate < policer->min_rate ||
18184bbdec80SJiri Pirko 			    policer->max_burst < policer->min_burst)) {
18194bbdec80SJiri Pirko 			err = -EINVAL;
18204bbdec80SJiri Pirko 			goto err_trap_policer_verify;
18214bbdec80SJiri Pirko 		}
18224bbdec80SJiri Pirko 
18234bbdec80SJiri Pirko 		err = devlink_trap_policer_register(devlink, policer);
18244bbdec80SJiri Pirko 		if (err)
18254bbdec80SJiri Pirko 			goto err_trap_policer_register;
18264bbdec80SJiri Pirko 	}
18274bbdec80SJiri Pirko 	return 0;
18284bbdec80SJiri Pirko 
18294bbdec80SJiri Pirko err_trap_policer_register:
18304bbdec80SJiri Pirko err_trap_policer_verify:
18314bbdec80SJiri Pirko 	for (i--; i >= 0; i--)
18324bbdec80SJiri Pirko 		devlink_trap_policer_unregister(devlink, &policers[i]);
18334bbdec80SJiri Pirko 	return err;
18344bbdec80SJiri Pirko }
18354bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_trap_policers_register);
18364bbdec80SJiri Pirko 
18374bbdec80SJiri Pirko /**
18384bbdec80SJiri Pirko  * devl_trap_policers_unregister - Unregister packet trap policers from devlink.
18394bbdec80SJiri Pirko  * @devlink: devlink.
18404bbdec80SJiri Pirko  * @policers: Packet trap policers.
18414bbdec80SJiri Pirko  * @policers_count: Count of provided packet trap policers.
18424bbdec80SJiri Pirko  */
18434bbdec80SJiri Pirko void
devl_trap_policers_unregister(struct devlink * devlink,const struct devlink_trap_policer * policers,size_t policers_count)18444bbdec80SJiri Pirko devl_trap_policers_unregister(struct devlink *devlink,
18454bbdec80SJiri Pirko 			      const struct devlink_trap_policer *policers,
18464bbdec80SJiri Pirko 			      size_t policers_count)
18474bbdec80SJiri Pirko {
18484bbdec80SJiri Pirko 	int i;
18494bbdec80SJiri Pirko 
18504bbdec80SJiri Pirko 	devl_assert_locked(devlink);
18514bbdec80SJiri Pirko 	for (i = policers_count - 1; i >= 0; i--)
18524bbdec80SJiri Pirko 		devlink_trap_policer_unregister(devlink, &policers[i]);
18534bbdec80SJiri Pirko }
18544bbdec80SJiri Pirko EXPORT_SYMBOL_GPL(devl_trap_policers_unregister);
1855