Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
   4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
   5 */
   6
   7#include <trace/events/devlink.h>
   8
   9#include "devl_internal.h"
  10
  11struct devlink_stats {
  12	u64_stats_t rx_bytes;
  13	u64_stats_t rx_packets;
  14	struct u64_stats_sync syncp;
  15};
  16
  17/**
  18 * struct devlink_trap_policer_item - Packet trap policer attributes.
  19 * @policer: Immutable packet trap policer attributes.
  20 * @rate: Rate in packets / sec.
  21 * @burst: Burst size in packets.
  22 * @list: trap_policer_list member.
  23 *
  24 * Describes packet trap policer attributes. Created by devlink during trap
  25 * policer registration.
  26 */
  27struct devlink_trap_policer_item {
  28	const struct devlink_trap_policer *policer;
  29	u64 rate;
  30	u64 burst;
  31	struct list_head list;
  32};
  33
  34/**
  35 * struct devlink_trap_group_item - Packet trap group attributes.
  36 * @group: Immutable packet trap group attributes.
  37 * @policer_item: Associated policer item. Can be NULL.
  38 * @list: trap_group_list member.
  39 * @stats: Trap group statistics.
  40 *
  41 * Describes packet trap group attributes. Created by devlink during trap
  42 * group registration.
  43 */
  44struct devlink_trap_group_item {
  45	const struct devlink_trap_group *group;
  46	struct devlink_trap_policer_item *policer_item;
  47	struct list_head list;
  48	struct devlink_stats __percpu *stats;
  49};
  50
  51/**
  52 * struct devlink_trap_item - Packet trap attributes.
  53 * @trap: Immutable packet trap attributes.
  54 * @group_item: Associated group item.
  55 * @list: trap_list member.
  56 * @action: Trap action.
  57 * @stats: Trap statistics.
  58 * @priv: Driver private information.
  59 *
  60 * Describes both mutable and immutable packet trap attributes. Created by
  61 * devlink during trap registration and used for all trap related operations.
  62 */
  63struct devlink_trap_item {
  64	const struct devlink_trap *trap;
  65	struct devlink_trap_group_item *group_item;
  66	struct list_head list;
  67	enum devlink_trap_action action;
  68	struct devlink_stats __percpu *stats;
  69	void *priv;
  70};
  71
  72static struct devlink_trap_policer_item *
  73devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
  74{
  75	struct devlink_trap_policer_item *policer_item;
  76
  77	list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
  78		if (policer_item->policer->id == id)
  79			return policer_item;
  80	}
  81
  82	return NULL;
  83}
  84
  85static struct devlink_trap_item *
  86devlink_trap_item_lookup(struct devlink *devlink, const char *name)
  87{
  88	struct devlink_trap_item *trap_item;
  89
  90	list_for_each_entry(trap_item, &devlink->trap_list, list) {
  91		if (!strcmp(trap_item->trap->name, name))
  92			return trap_item;
  93	}
  94
  95	return NULL;
  96}
  97
  98static struct devlink_trap_item *
  99devlink_trap_item_get_from_info(struct devlink *devlink,
 100				struct genl_info *info)
 101{
 102	struct nlattr *attr;
 103
 104	if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
 105		return NULL;
 106	attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
 107
 108	return devlink_trap_item_lookup(devlink, nla_data(attr));
 109}
 110
 111static int
 112devlink_trap_action_get_from_info(struct genl_info *info,
 113				  enum devlink_trap_action *p_trap_action)
 114{
 115	u8 val;
 116
 117	val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
 118	switch (val) {
 119	case DEVLINK_TRAP_ACTION_DROP:
 120	case DEVLINK_TRAP_ACTION_TRAP:
 121	case DEVLINK_TRAP_ACTION_MIRROR:
 122		*p_trap_action = val;
 123		break;
 124	default:
 125		return -EINVAL;
 126	}
 127
 128	return 0;
 129}
 130
 131static int devlink_trap_metadata_put(struct sk_buff *msg,
 132				     const struct devlink_trap *trap)
 133{
 134	struct nlattr *attr;
 135
 136	attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
 137	if (!attr)
 138		return -EMSGSIZE;
 139
 140	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
 141	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
 142		goto nla_put_failure;
 143	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
 144	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
 145		goto nla_put_failure;
 146
 147	nla_nest_end(msg, attr);
 148
 149	return 0;
 150
 151nla_put_failure:
 152	nla_nest_cancel(msg, attr);
 153	return -EMSGSIZE;
 154}
 155
 156static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
 157				    struct devlink_stats *stats)
 158{
 159	int i;
 160
 161	memset(stats, 0, sizeof(*stats));
 162	for_each_possible_cpu(i) {
 163		struct devlink_stats *cpu_stats;
 164		u64 rx_packets, rx_bytes;
 165		unsigned int start;
 166
 167		cpu_stats = per_cpu_ptr(trap_stats, i);
 168		do {
 169			start = u64_stats_fetch_begin(&cpu_stats->syncp);
 170			rx_packets = u64_stats_read(&cpu_stats->rx_packets);
 171			rx_bytes = u64_stats_read(&cpu_stats->rx_bytes);
 172		} while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
 173
 174		u64_stats_add(&stats->rx_packets, rx_packets);
 175		u64_stats_add(&stats->rx_bytes, rx_bytes);
 176	}
 177}
 178
 179static int
 180devlink_trap_group_stats_put(struct sk_buff *msg,
 181			     struct devlink_stats __percpu *trap_stats)
 182{
 183	struct devlink_stats stats;
 184	struct nlattr *attr;
 185
 186	devlink_trap_stats_read(trap_stats, &stats);
 187
 188	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
 189	if (!attr)
 190		return -EMSGSIZE;
 191
 192	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
 193			       u64_stats_read(&stats.rx_packets)))
 194		goto nla_put_failure;
 195
 196	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
 197			       u64_stats_read(&stats.rx_bytes)))
 198		goto nla_put_failure;
 199
 200	nla_nest_end(msg, attr);
 201
 202	return 0;
 203
 204nla_put_failure:
 205	nla_nest_cancel(msg, attr);
 206	return -EMSGSIZE;
 207}
 208
 209static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
 210				  const struct devlink_trap_item *trap_item)
 211{
 212	struct devlink_stats stats;
 213	struct nlattr *attr;
 214	u64 drops = 0;
 215	int err;
 216
 217	if (devlink->ops->trap_drop_counter_get) {
 218		err = devlink->ops->trap_drop_counter_get(devlink,
 219							  trap_item->trap,
 220							  &drops);
 221		if (err)
 222			return err;
 223	}
 224
 225	devlink_trap_stats_read(trap_item->stats, &stats);
 226
 227	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
 228	if (!attr)
 229		return -EMSGSIZE;
 230
 231	if (devlink->ops->trap_drop_counter_get &&
 232	    devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
 233		goto nla_put_failure;
 234
 235	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
 236			       u64_stats_read(&stats.rx_packets)))
 237		goto nla_put_failure;
 238
 239	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
 240			       u64_stats_read(&stats.rx_bytes)))
 241		goto nla_put_failure;
 242
 243	nla_nest_end(msg, attr);
 244
 245	return 0;
 246
 247nla_put_failure:
 248	nla_nest_cancel(msg, attr);
 249	return -EMSGSIZE;
 250}
 251
 252static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
 253				const struct devlink_trap_item *trap_item,
 254				enum devlink_command cmd, u32 portid, u32 seq,
 255				int flags)
 256{
 257	struct devlink_trap_group_item *group_item = trap_item->group_item;
 258	void *hdr;
 259	int err;
 260
 261	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
 262	if (!hdr)
 263		return -EMSGSIZE;
 264
 265	if (devlink_nl_put_handle(msg, devlink))
 266		goto nla_put_failure;
 267
 268	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
 269			   group_item->group->name))
 270		goto nla_put_failure;
 271
 272	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
 273		goto nla_put_failure;
 274
 275	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
 276		goto nla_put_failure;
 277
 278	if (trap_item->trap->generic &&
 279	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
 280		goto nla_put_failure;
 281
 282	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
 283		goto nla_put_failure;
 284
 285	err = devlink_trap_metadata_put(msg, trap_item->trap);
 286	if (err)
 287		goto nla_put_failure;
 288
 289	err = devlink_trap_stats_put(msg, devlink, trap_item);
 290	if (err)
 291		goto nla_put_failure;
 292
 293	genlmsg_end(msg, hdr);
 294
 295	return 0;
 296
 297nla_put_failure:
 298	genlmsg_cancel(msg, hdr);
 299	return -EMSGSIZE;
 300}
 301
 302int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info)
 303{
 304	struct netlink_ext_ack *extack = info->extack;
 305	struct devlink *devlink = info->user_ptr[0];
 306	struct devlink_trap_item *trap_item;
 307	struct sk_buff *msg;
 308	int err;
 309
 310	if (list_empty(&devlink->trap_list))
 311		return -EOPNOTSUPP;
 312
 313	trap_item = devlink_trap_item_get_from_info(devlink, info);
 314	if (!trap_item) {
 315		NL_SET_ERR_MSG(extack, "Device did not register this trap");
 316		return -ENOENT;
 317	}
 318
 319	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 320	if (!msg)
 321		return -ENOMEM;
 322
 323	err = devlink_nl_trap_fill(msg, devlink, trap_item,
 324				   DEVLINK_CMD_TRAP_NEW, info->snd_portid,
 325				   info->snd_seq, 0);
 326	if (err)
 327		goto err_trap_fill;
 328
 329	return genlmsg_reply(msg, info);
 330
 331err_trap_fill:
 332	nlmsg_free(msg);
 333	return err;
 334}
 335
 336static int devlink_nl_trap_get_dump_one(struct sk_buff *msg,
 337					struct devlink *devlink,
 338					struct netlink_callback *cb, int flags)
 339{
 340	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
 341	struct devlink_trap_item *trap_item;
 342	int idx = 0;
 343	int err = 0;
 344
 345	list_for_each_entry(trap_item, &devlink->trap_list, list) {
 346		if (idx < state->idx) {
 347			idx++;
 348			continue;
 349		}
 350		err = devlink_nl_trap_fill(msg, devlink, trap_item,
 351					   DEVLINK_CMD_TRAP_NEW,
 352					   NETLINK_CB(cb->skb).portid,
 353					   cb->nlh->nlmsg_seq, flags);
 354		if (err) {
 355			state->idx = idx;
 356			break;
 357		}
 358		idx++;
 359	}
 360
 361	return err;
 362}
 363
 364int devlink_nl_trap_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 365{
 366	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_get_dump_one);
 367}
 368
 369static int __devlink_trap_action_set(struct devlink *devlink,
 370				     struct devlink_trap_item *trap_item,
 371				     enum devlink_trap_action trap_action,
 372				     struct netlink_ext_ack *extack)
 373{
 374	int err;
 375
 376	if (trap_item->action != trap_action &&
 377	    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
 378		NL_SET_ERR_MSG(extack, "Cannot change action of non-drop traps. Skipping");
 379		return 0;
 380	}
 381
 382	err = devlink->ops->trap_action_set(devlink, trap_item->trap,
 383					    trap_action, extack);
 384	if (err)
 385		return err;
 386
 387	trap_item->action = trap_action;
 388
 389	return 0;
 390}
 391
 392static int devlink_trap_action_set(struct devlink *devlink,
 393				   struct devlink_trap_item *trap_item,
 394				   struct genl_info *info)
 395{
 396	enum devlink_trap_action trap_action;
 397	int err;
 398
 399	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
 400		return 0;
 401
 402	err = devlink_trap_action_get_from_info(info, &trap_action);
 403	if (err) {
 404		NL_SET_ERR_MSG(info->extack, "Invalid trap action");
 405		return -EINVAL;
 406	}
 407
 408	return __devlink_trap_action_set(devlink, trap_item, trap_action,
 409					 info->extack);
 410}
 411
 412int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info)
 413{
 414	struct netlink_ext_ack *extack = info->extack;
 415	struct devlink *devlink = info->user_ptr[0];
 416	struct devlink_trap_item *trap_item;
 417
 418	if (list_empty(&devlink->trap_list))
 419		return -EOPNOTSUPP;
 420
 421	trap_item = devlink_trap_item_get_from_info(devlink, info);
 422	if (!trap_item) {
 423		NL_SET_ERR_MSG(extack, "Device did not register this trap");
 424		return -ENOENT;
 425	}
 426
 427	return devlink_trap_action_set(devlink, trap_item, info);
 428}
 429
 430static struct devlink_trap_group_item *
 431devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
 432{
 433	struct devlink_trap_group_item *group_item;
 434
 435	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
 436		if (!strcmp(group_item->group->name, name))
 437			return group_item;
 438	}
 439
 440	return NULL;
 441}
 442
 443static struct devlink_trap_group_item *
 444devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
 445{
 446	struct devlink_trap_group_item *group_item;
 447
 448	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
 449		if (group_item->group->id == id)
 450			return group_item;
 451	}
 452
 453	return NULL;
 454}
 455
 456static struct devlink_trap_group_item *
 457devlink_trap_group_item_get_from_info(struct devlink *devlink,
 458				      struct genl_info *info)
 459{
 460	char *name;
 461
 462	if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
 463		return NULL;
 464	name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
 465
 466	return devlink_trap_group_item_lookup(devlink, name);
 467}
 468
 469static int
 470devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
 471			   const struct devlink_trap_group_item *group_item,
 472			   enum devlink_command cmd, u32 portid, u32 seq,
 473			   int flags)
 474{
 475	void *hdr;
 476	int err;
 477
 478	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
 479	if (!hdr)
 480		return -EMSGSIZE;
 481
 482	if (devlink_nl_put_handle(msg, devlink))
 483		goto nla_put_failure;
 484
 485	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
 486			   group_item->group->name))
 487		goto nla_put_failure;
 488
 489	if (group_item->group->generic &&
 490	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
 491		goto nla_put_failure;
 492
 493	if (group_item->policer_item &&
 494	    nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
 495			group_item->policer_item->policer->id))
 496		goto nla_put_failure;
 497
 498	err = devlink_trap_group_stats_put(msg, group_item->stats);
 499	if (err)
 500		goto nla_put_failure;
 501
 502	genlmsg_end(msg, hdr);
 503
 504	return 0;
 505
 506nla_put_failure:
 507	genlmsg_cancel(msg, hdr);
 508	return -EMSGSIZE;
 509}
 510
 511int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info)
 512{
 513	struct netlink_ext_ack *extack = info->extack;
 514	struct devlink *devlink = info->user_ptr[0];
 515	struct devlink_trap_group_item *group_item;
 516	struct sk_buff *msg;
 517	int err;
 518
 519	if (list_empty(&devlink->trap_group_list))
 520		return -EOPNOTSUPP;
 521
 522	group_item = devlink_trap_group_item_get_from_info(devlink, info);
 523	if (!group_item) {
 524		NL_SET_ERR_MSG(extack, "Device did not register this trap group");
 525		return -ENOENT;
 526	}
 527
 528	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 529	if (!msg)
 530		return -ENOMEM;
 531
 532	err = devlink_nl_trap_group_fill(msg, devlink, group_item,
 533					 DEVLINK_CMD_TRAP_GROUP_NEW,
 534					 info->snd_portid, info->snd_seq, 0);
 535	if (err)
 536		goto err_trap_group_fill;
 537
 538	return genlmsg_reply(msg, info);
 539
 540err_trap_group_fill:
 541	nlmsg_free(msg);
 542	return err;
 543}
 544
 545static int devlink_nl_trap_group_get_dump_one(struct sk_buff *msg,
 546					      struct devlink *devlink,
 547					      struct netlink_callback *cb,
 548					      int flags)
 549{
 550	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
 551	struct devlink_trap_group_item *group_item;
 552	int idx = 0;
 553	int err = 0;
 554
 555	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
 556		if (idx < state->idx) {
 557			idx++;
 558			continue;
 559		}
 560		err = devlink_nl_trap_group_fill(msg, devlink, group_item,
 561						 DEVLINK_CMD_TRAP_GROUP_NEW,
 562						 NETLINK_CB(cb->skb).portid,
 563						 cb->nlh->nlmsg_seq, flags);
 564		if (err) {
 565			state->idx = idx;
 566			break;
 567		}
 568		idx++;
 569	}
 570
 571	return err;
 572}
 573
 574int devlink_nl_trap_group_get_dumpit(struct sk_buff *skb,
 575				     struct netlink_callback *cb)
 576{
 577	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_group_get_dump_one);
 578}
 579
 580static int
 581__devlink_trap_group_action_set(struct devlink *devlink,
 582				struct devlink_trap_group_item *group_item,
 583				enum devlink_trap_action trap_action,
 584				struct netlink_ext_ack *extack)
 585{
 586	const char *group_name = group_item->group->name;
 587	struct devlink_trap_item *trap_item;
 588	int err;
 589
 590	if (devlink->ops->trap_group_action_set) {
 591		err = devlink->ops->trap_group_action_set(devlink, group_item->group,
 592							  trap_action, extack);
 593		if (err)
 594			return err;
 595
 596		list_for_each_entry(trap_item, &devlink->trap_list, list) {
 597			if (strcmp(trap_item->group_item->group->name, group_name))
 598				continue;
 599			if (trap_item->action != trap_action &&
 600			    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
 601				continue;
 602			trap_item->action = trap_action;
 603		}
 604
 605		return 0;
 606	}
 607
 608	list_for_each_entry(trap_item, &devlink->trap_list, list) {
 609		if (strcmp(trap_item->group_item->group->name, group_name))
 610			continue;
 611		err = __devlink_trap_action_set(devlink, trap_item,
 612						trap_action, extack);
 613		if (err)
 614			return err;
 615	}
 616
 617	return 0;
 618}
 619
 620static int
 621devlink_trap_group_action_set(struct devlink *devlink,
 622			      struct devlink_trap_group_item *group_item,
 623			      struct genl_info *info, bool *p_modified)
 624{
 625	enum devlink_trap_action trap_action;
 626	int err;
 627
 628	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
 629		return 0;
 630
 631	err = devlink_trap_action_get_from_info(info, &trap_action);
 632	if (err) {
 633		NL_SET_ERR_MSG(info->extack, "Invalid trap action");
 634		return -EINVAL;
 635	}
 636
 637	err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
 638					      info->extack);
 639	if (err)
 640		return err;
 641
 642	*p_modified = true;
 643
 644	return 0;
 645}
 646
 647static int devlink_trap_group_set(struct devlink *devlink,
 648				  struct devlink_trap_group_item *group_item,
 649				  struct genl_info *info)
 650{
 651	struct devlink_trap_policer_item *policer_item;
 652	struct netlink_ext_ack *extack = info->extack;
 653	const struct devlink_trap_policer *policer;
 654	struct nlattr **attrs = info->attrs;
 655	u32 policer_id;
 656	int err;
 657
 658	if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
 659		return 0;
 660
 661	if (!devlink->ops->trap_group_set)
 662		return -EOPNOTSUPP;
 663
 664	policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
 665	policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
 666	if (policer_id && !policer_item) {
 667		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
 668		return -ENOENT;
 669	}
 670	policer = policer_item ? policer_item->policer : NULL;
 671
 672	err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
 673					   extack);
 674	if (err)
 675		return err;
 676
 677	group_item->policer_item = policer_item;
 678
 679	return 0;
 680}
 681
 682int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info)
 683{
 684	struct netlink_ext_ack *extack = info->extack;
 685	struct devlink *devlink = info->user_ptr[0];
 686	struct devlink_trap_group_item *group_item;
 687	bool modified = false;
 688	int err;
 689
 690	if (list_empty(&devlink->trap_group_list))
 691		return -EOPNOTSUPP;
 692
 693	group_item = devlink_trap_group_item_get_from_info(devlink, info);
 694	if (!group_item) {
 695		NL_SET_ERR_MSG(extack, "Device did not register this trap group");
 696		return -ENOENT;
 697	}
 698
 699	err = devlink_trap_group_action_set(devlink, group_item, info,
 700					    &modified);
 701	if (err)
 702		return err;
 703
 704	err = devlink_trap_group_set(devlink, group_item, info);
 705	if (err)
 706		goto err_trap_group_set;
 707
 708	return 0;
 709
 710err_trap_group_set:
 711	if (modified)
 712		NL_SET_ERR_MSG(extack, "Trap group set failed, but some changes were committed already");
 713	return err;
 714}
 715
 716static struct devlink_trap_policer_item *
 717devlink_trap_policer_item_get_from_info(struct devlink *devlink,
 718					struct genl_info *info)
 719{
 720	u32 id;
 721
 722	if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
 723		return NULL;
 724	id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
 725
 726	return devlink_trap_policer_item_lookup(devlink, id);
 727}
 728
 729static int
 730devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
 731			       const struct devlink_trap_policer *policer)
 732{
 733	struct nlattr *attr;
 734	u64 drops;
 735	int err;
 736
 737	if (!devlink->ops->trap_policer_counter_get)
 738		return 0;
 739
 740	err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
 741	if (err)
 742		return err;
 743
 744	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
 745	if (!attr)
 746		return -EMSGSIZE;
 747
 748	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
 749		goto nla_put_failure;
 750
 751	nla_nest_end(msg, attr);
 752
 753	return 0;
 754
 755nla_put_failure:
 756	nla_nest_cancel(msg, attr);
 757	return -EMSGSIZE;
 758}
 759
 760static int
 761devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
 762			     const struct devlink_trap_policer_item *policer_item,
 763			     enum devlink_command cmd, u32 portid, u32 seq,
 764			     int flags)
 765{
 766	void *hdr;
 767	int err;
 768
 769	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
 770	if (!hdr)
 771		return -EMSGSIZE;
 772
 773	if (devlink_nl_put_handle(msg, devlink))
 774		goto nla_put_failure;
 775
 776	if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
 777			policer_item->policer->id))
 778		goto nla_put_failure;
 779
 780	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
 781			       policer_item->rate))
 782		goto nla_put_failure;
 783
 784	if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
 785			       policer_item->burst))
 786		goto nla_put_failure;
 787
 788	err = devlink_trap_policer_stats_put(msg, devlink,
 789					     policer_item->policer);
 790	if (err)
 791		goto nla_put_failure;
 792
 793	genlmsg_end(msg, hdr);
 794
 795	return 0;
 796
 797nla_put_failure:
 798	genlmsg_cancel(msg, hdr);
 799	return -EMSGSIZE;
 800}
 801
 802int devlink_nl_trap_policer_get_doit(struct sk_buff *skb,
 803				     struct genl_info *info)
 804{
 805	struct devlink_trap_policer_item *policer_item;
 806	struct netlink_ext_ack *extack = info->extack;
 807	struct devlink *devlink = info->user_ptr[0];
 808	struct sk_buff *msg;
 809	int err;
 810
 811	if (list_empty(&devlink->trap_policer_list))
 812		return -EOPNOTSUPP;
 813
 814	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
 815	if (!policer_item) {
 816		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
 817		return -ENOENT;
 818	}
 819
 820	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 821	if (!msg)
 822		return -ENOMEM;
 823
 824	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
 825					   DEVLINK_CMD_TRAP_POLICER_NEW,
 826					   info->snd_portid, info->snd_seq, 0);
 827	if (err)
 828		goto err_trap_policer_fill;
 829
 830	return genlmsg_reply(msg, info);
 831
 832err_trap_policer_fill:
 833	nlmsg_free(msg);
 834	return err;
 835}
 836
 837static int devlink_nl_trap_policer_get_dump_one(struct sk_buff *msg,
 838						struct devlink *devlink,
 839						struct netlink_callback *cb,
 840						int flags)
 841{
 842	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
 843	struct devlink_trap_policer_item *policer_item;
 844	int idx = 0;
 845	int err = 0;
 846
 847	list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
 848		if (idx < state->idx) {
 849			idx++;
 850			continue;
 851		}
 852		err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
 853						   DEVLINK_CMD_TRAP_POLICER_NEW,
 854						   NETLINK_CB(cb->skb).portid,
 855						   cb->nlh->nlmsg_seq, flags);
 856		if (err) {
 857			state->idx = idx;
 858			break;
 859		}
 860		idx++;
 861	}
 862
 863	return err;
 864}
 865
 866int devlink_nl_trap_policer_get_dumpit(struct sk_buff *skb,
 867				       struct netlink_callback *cb)
 868{
 869	return devlink_nl_dumpit(skb, cb, devlink_nl_trap_policer_get_dump_one);
 870}
 871
 872static int
 873devlink_trap_policer_set(struct devlink *devlink,
 874			 struct devlink_trap_policer_item *policer_item,
 875			 struct genl_info *info)
 876{
 877	struct netlink_ext_ack *extack = info->extack;
 878	struct nlattr **attrs = info->attrs;
 879	u64 rate, burst;
 880	int err;
 881
 882	rate = policer_item->rate;
 883	burst = policer_item->burst;
 884
 885	if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
 886		rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
 887
 888	if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
 889		burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
 890
 891	if (rate < policer_item->policer->min_rate) {
 892		NL_SET_ERR_MSG(extack, "Policer rate lower than limit");
 893		return -EINVAL;
 894	}
 895
 896	if (rate > policer_item->policer->max_rate) {
 897		NL_SET_ERR_MSG(extack, "Policer rate higher than limit");
 898		return -EINVAL;
 899	}
 900
 901	if (burst < policer_item->policer->min_burst) {
 902		NL_SET_ERR_MSG(extack, "Policer burst size lower than limit");
 903		return -EINVAL;
 904	}
 905
 906	if (burst > policer_item->policer->max_burst) {
 907		NL_SET_ERR_MSG(extack, "Policer burst size higher than limit");
 908		return -EINVAL;
 909	}
 910
 911	err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
 912					     rate, burst, info->extack);
 913	if (err)
 914		return err;
 915
 916	policer_item->rate = rate;
 917	policer_item->burst = burst;
 918
 919	return 0;
 920}
 921
 922int devlink_nl_trap_policer_set_doit(struct sk_buff *skb,
 923				     struct genl_info *info)
 924{
 925	struct devlink_trap_policer_item *policer_item;
 926	struct netlink_ext_ack *extack = info->extack;
 927	struct devlink *devlink = info->user_ptr[0];
 928
 929	if (list_empty(&devlink->trap_policer_list))
 930		return -EOPNOTSUPP;
 931
 932	if (!devlink->ops->trap_policer_set)
 933		return -EOPNOTSUPP;
 934
 935	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
 936	if (!policer_item) {
 937		NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
 938		return -ENOENT;
 939	}
 940
 941	return devlink_trap_policer_set(devlink, policer_item, info);
 942}
 943
 944#define DEVLINK_TRAP(_id, _type)					      \
 945	{								      \
 946		.type = DEVLINK_TRAP_TYPE_##_type,			      \
 947		.id = DEVLINK_TRAP_GENERIC_ID_##_id,			      \
 948		.name = DEVLINK_TRAP_GENERIC_NAME_##_id,		      \
 949	}
 950
 951static const struct devlink_trap devlink_trap_generic[] = {
 952	DEVLINK_TRAP(SMAC_MC, DROP),
 953	DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
 954	DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
 955	DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
 956	DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
 957	DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
 958	DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
 959	DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
 960	DEVLINK_TRAP(TAIL_DROP, DROP),
 961	DEVLINK_TRAP(NON_IP_PACKET, DROP),
 962	DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
 963	DEVLINK_TRAP(DIP_LB, DROP),
 964	DEVLINK_TRAP(SIP_MC, DROP),
 965	DEVLINK_TRAP(SIP_LB, DROP),
 966	DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
 967	DEVLINK_TRAP(IPV4_SIP_BC, DROP),
 968	DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
 969	DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
 970	DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
 971	DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
 972	DEVLINK_TRAP(RPF, EXCEPTION),
 973	DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
 974	DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
 975	DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
 976	DEVLINK_TRAP(NON_ROUTABLE, DROP),
 977	DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
 978	DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
 979	DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
 980	DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
 981	DEVLINK_TRAP(STP, CONTROL),
 982	DEVLINK_TRAP(LACP, CONTROL),
 983	DEVLINK_TRAP(LLDP, CONTROL),
 984	DEVLINK_TRAP(IGMP_QUERY, CONTROL),
 985	DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
 986	DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
 987	DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
 988	DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
 989	DEVLINK_TRAP(MLD_QUERY, CONTROL),
 990	DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
 991	DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
 992	DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
 993	DEVLINK_TRAP(IPV4_DHCP, CONTROL),
 994	DEVLINK_TRAP(IPV6_DHCP, CONTROL),
 995	DEVLINK_TRAP(ARP_REQUEST, CONTROL),
 996	DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
 997	DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
 998	DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
 999	DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
1000	DEVLINK_TRAP(IPV4_BFD, CONTROL),
1001	DEVLINK_TRAP(IPV6_BFD, CONTROL),
1002	DEVLINK_TRAP(IPV4_OSPF, CONTROL),
1003	DEVLINK_TRAP(IPV6_OSPF, CONTROL),
1004	DEVLINK_TRAP(IPV4_BGP, CONTROL),
1005	DEVLINK_TRAP(IPV6_BGP, CONTROL),
1006	DEVLINK_TRAP(IPV4_VRRP, CONTROL),
1007	DEVLINK_TRAP(IPV6_VRRP, CONTROL),
1008	DEVLINK_TRAP(IPV4_PIM, CONTROL),
1009	DEVLINK_TRAP(IPV6_PIM, CONTROL),
1010	DEVLINK_TRAP(UC_LB, CONTROL),
1011	DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
1012	DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
1013	DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
1014	DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
1015	DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
1016	DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
1017	DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
1018	DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
1019	DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
1020	DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
1021	DEVLINK_TRAP(PTP_EVENT, CONTROL),
1022	DEVLINK_TRAP(PTP_GENERAL, CONTROL),
1023	DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
1024	DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
1025	DEVLINK_TRAP(EARLY_DROP, DROP),
1026	DEVLINK_TRAP(VXLAN_PARSING, DROP),
1027	DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
1028	DEVLINK_TRAP(VLAN_PARSING, DROP),
1029	DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
1030	DEVLINK_TRAP(MPLS_PARSING, DROP),
1031	DEVLINK_TRAP(ARP_PARSING, DROP),
1032	DEVLINK_TRAP(IP_1_PARSING, DROP),
1033	DEVLINK_TRAP(IP_N_PARSING, DROP),
1034	DEVLINK_TRAP(GRE_PARSING, DROP),
1035	DEVLINK_TRAP(UDP_PARSING, DROP),
1036	DEVLINK_TRAP(TCP_PARSING, DROP),
1037	DEVLINK_TRAP(IPSEC_PARSING, DROP),
1038	DEVLINK_TRAP(SCTP_PARSING, DROP),
1039	DEVLINK_TRAP(DCCP_PARSING, DROP),
1040	DEVLINK_TRAP(GTP_PARSING, DROP),
1041	DEVLINK_TRAP(ESP_PARSING, DROP),
1042	DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP),
1043	DEVLINK_TRAP(DMAC_FILTER, DROP),
1044	DEVLINK_TRAP(EAPOL, CONTROL),
1045	DEVLINK_TRAP(LOCKED_PORT, DROP),
1046};
1047
1048#define DEVLINK_TRAP_GROUP(_id)						      \
1049	{								      \
1050		.id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id,		      \
1051		.name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id,		      \
1052	}
1053
1054static const struct devlink_trap_group devlink_trap_group_generic[] = {
1055	DEVLINK_TRAP_GROUP(L2_DROPS),
1056	DEVLINK_TRAP_GROUP(L3_DROPS),
1057	DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
1058	DEVLINK_TRAP_GROUP(BUFFER_DROPS),
1059	DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
1060	DEVLINK_TRAP_GROUP(ACL_DROPS),
1061	DEVLINK_TRAP_GROUP(STP),
1062	DEVLINK_TRAP_GROUP(LACP),
1063	DEVLINK_TRAP_GROUP(LLDP),
1064	DEVLINK_TRAP_GROUP(MC_SNOOPING),
1065	DEVLINK_TRAP_GROUP(DHCP),
1066	DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
1067	DEVLINK_TRAP_GROUP(BFD),
1068	DEVLINK_TRAP_GROUP(OSPF),
1069	DEVLINK_TRAP_GROUP(BGP),
1070	DEVLINK_TRAP_GROUP(VRRP),
1071	DEVLINK_TRAP_GROUP(PIM),
1072	DEVLINK_TRAP_GROUP(UC_LB),
1073	DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
1074	DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
1075	DEVLINK_TRAP_GROUP(IPV6),
1076	DEVLINK_TRAP_GROUP(PTP_EVENT),
1077	DEVLINK_TRAP_GROUP(PTP_GENERAL),
1078	DEVLINK_TRAP_GROUP(ACL_SAMPLE),
1079	DEVLINK_TRAP_GROUP(ACL_TRAP),
1080	DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
1081	DEVLINK_TRAP_GROUP(EAPOL),
1082};
1083
1084static int devlink_trap_generic_verify(const struct devlink_trap *trap)
1085{
1086	if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
1087		return -EINVAL;
1088
1089	if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
1090		return -EINVAL;
1091
1092	if (trap->type != devlink_trap_generic[trap->id].type)
1093		return -EINVAL;
1094
1095	return 0;
1096}
1097
1098static int devlink_trap_driver_verify(const struct devlink_trap *trap)
1099{
1100	int i;
1101
1102	if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
1103		return -EINVAL;
1104
1105	for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
1106		if (!strcmp(trap->name, devlink_trap_generic[i].name))
1107			return -EEXIST;
1108	}
1109
1110	return 0;
1111}
1112
1113static int devlink_trap_verify(const struct devlink_trap *trap)
1114{
1115	if (!trap || !trap->name)
1116		return -EINVAL;
1117
1118	if (trap->generic)
1119		return devlink_trap_generic_verify(trap);
1120	else
1121		return devlink_trap_driver_verify(trap);
1122}
1123
1124static int
1125devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
1126{
1127	if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
1128		return -EINVAL;
1129
1130	if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
1131		return -EINVAL;
1132
1133	return 0;
1134}
1135
1136static int
1137devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
1138{
1139	int i;
1140
1141	if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
1142		return -EINVAL;
1143
1144	for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
1145		if (!strcmp(group->name, devlink_trap_group_generic[i].name))
1146			return -EEXIST;
1147	}
1148
1149	return 0;
1150}
1151
1152static int devlink_trap_group_verify(const struct devlink_trap_group *group)
1153{
1154	if (group->generic)
1155		return devlink_trap_group_generic_verify(group);
1156	else
1157		return devlink_trap_group_driver_verify(group);
1158}
1159
1160static void
1161devlink_trap_group_notify(struct devlink *devlink,
1162			  const struct devlink_trap_group_item *group_item,
1163			  enum devlink_command cmd)
1164{
1165	struct sk_buff *msg;
1166	int err;
1167
1168	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
1169		     cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
1170
1171	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1172		return;
1173
1174	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1175	if (!msg)
1176		return;
1177
1178	err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
1179					 0);
1180	if (err) {
1181		nlmsg_free(msg);
1182		return;
1183	}
1184
1185	devlink_nl_notify_send(devlink, msg);
1186}
1187
1188void devlink_trap_groups_notify_register(struct devlink *devlink)
1189{
1190	struct devlink_trap_group_item *group_item;
1191
1192	list_for_each_entry(group_item, &devlink->trap_group_list, list)
1193		devlink_trap_group_notify(devlink, group_item,
1194					  DEVLINK_CMD_TRAP_GROUP_NEW);
1195}
1196
1197void devlink_trap_groups_notify_unregister(struct devlink *devlink)
1198{
1199	struct devlink_trap_group_item *group_item;
1200
1201	list_for_each_entry_reverse(group_item, &devlink->trap_group_list, list)
1202		devlink_trap_group_notify(devlink, group_item,
1203					  DEVLINK_CMD_TRAP_GROUP_DEL);
1204}
1205
1206static int
1207devlink_trap_item_group_link(struct devlink *devlink,
1208			     struct devlink_trap_item *trap_item)
1209{
1210	u16 group_id = trap_item->trap->init_group_id;
1211	struct devlink_trap_group_item *group_item;
1212
1213	group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
1214	if (WARN_ON_ONCE(!group_item))
1215		return -EINVAL;
1216
1217	trap_item->group_item = group_item;
1218
1219	return 0;
1220}
1221
1222static void devlink_trap_notify(struct devlink *devlink,
1223				const struct devlink_trap_item *trap_item,
1224				enum devlink_command cmd)
1225{
1226	struct sk_buff *msg;
1227	int err;
1228
1229	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
1230		     cmd != DEVLINK_CMD_TRAP_DEL);
1231
1232	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1233		return;
1234
1235	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1236	if (!msg)
1237		return;
1238
1239	err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
1240	if (err) {
1241		nlmsg_free(msg);
1242		return;
1243	}
1244
1245	devlink_nl_notify_send(devlink, msg);
1246}
1247
1248void devlink_traps_notify_register(struct devlink *devlink)
1249{
1250	struct devlink_trap_item *trap_item;
1251
1252	list_for_each_entry(trap_item, &devlink->trap_list, list)
1253		devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
1254}
1255
1256void devlink_traps_notify_unregister(struct devlink *devlink)
1257{
1258	struct devlink_trap_item *trap_item;
1259
1260	list_for_each_entry_reverse(trap_item, &devlink->trap_list, list)
1261		devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
1262}
1263
1264static int
1265devlink_trap_register(struct devlink *devlink,
1266		      const struct devlink_trap *trap, void *priv)
1267{
1268	struct devlink_trap_item *trap_item;
1269	int err;
1270
1271	if (devlink_trap_item_lookup(devlink, trap->name))
1272		return -EEXIST;
1273
1274	trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
1275	if (!trap_item)
1276		return -ENOMEM;
1277
1278	trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
1279	if (!trap_item->stats) {
1280		err = -ENOMEM;
1281		goto err_stats_alloc;
1282	}
1283
1284	trap_item->trap = trap;
1285	trap_item->action = trap->init_action;
1286	trap_item->priv = priv;
1287
1288	err = devlink_trap_item_group_link(devlink, trap_item);
1289	if (err)
1290		goto err_group_link;
1291
1292	err = devlink->ops->trap_init(devlink, trap, trap_item);
1293	if (err)
1294		goto err_trap_init;
1295
1296	list_add_tail(&trap_item->list, &devlink->trap_list);
1297	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
1298
1299	return 0;
1300
1301err_trap_init:
1302err_group_link:
1303	free_percpu(trap_item->stats);
1304err_stats_alloc:
1305	kfree(trap_item);
1306	return err;
1307}
1308
1309static void devlink_trap_unregister(struct devlink *devlink,
1310				    const struct devlink_trap *trap)
1311{
1312	struct devlink_trap_item *trap_item;
1313
1314	trap_item = devlink_trap_item_lookup(devlink, trap->name);
1315	if (WARN_ON_ONCE(!trap_item))
1316		return;
1317
1318	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
1319	list_del(&trap_item->list);
1320	if (devlink->ops->trap_fini)
1321		devlink->ops->trap_fini(devlink, trap, trap_item);
1322	free_percpu(trap_item->stats);
1323	kfree(trap_item);
1324}
1325
1326static void devlink_trap_disable(struct devlink *devlink,
1327				 const struct devlink_trap *trap)
1328{
1329	struct devlink_trap_item *trap_item;
1330
1331	trap_item = devlink_trap_item_lookup(devlink, trap->name);
1332	if (WARN_ON_ONCE(!trap_item))
1333		return;
1334
1335	devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
1336				      NULL);
1337	trap_item->action = DEVLINK_TRAP_ACTION_DROP;
1338}
1339
1340/**
1341 * devl_traps_register - Register packet traps with devlink.
1342 * @devlink: devlink.
1343 * @traps: Packet traps.
1344 * @traps_count: Count of provided packet traps.
1345 * @priv: Driver private information.
1346 *
1347 * Return: Non-zero value on failure.
1348 */
1349int devl_traps_register(struct devlink *devlink,
1350			const struct devlink_trap *traps,
1351			size_t traps_count, void *priv)
1352{
1353	int i, err;
1354
1355	if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
1356		return -EINVAL;
1357
1358	devl_assert_locked(devlink);
1359	for (i = 0; i < traps_count; i++) {
1360		const struct devlink_trap *trap = &traps[i];
1361
1362		err = devlink_trap_verify(trap);
1363		if (err)
1364			goto err_trap_verify;
1365
1366		err = devlink_trap_register(devlink, trap, priv);
1367		if (err)
1368			goto err_trap_register;
1369	}
1370
1371	return 0;
1372
1373err_trap_register:
1374err_trap_verify:
1375	for (i--; i >= 0; i--)
1376		devlink_trap_unregister(devlink, &traps[i]);
1377	return err;
1378}
1379EXPORT_SYMBOL_GPL(devl_traps_register);
1380
1381/**
1382 * devlink_traps_register - Register packet traps with devlink.
1383 * @devlink: devlink.
1384 * @traps: Packet traps.
1385 * @traps_count: Count of provided packet traps.
1386 * @priv: Driver private information.
1387 *
1388 * Context: Takes and release devlink->lock <mutex>.
1389 *
1390 * Return: Non-zero value on failure.
1391 */
1392int devlink_traps_register(struct devlink *devlink,
1393			   const struct devlink_trap *traps,
1394			   size_t traps_count, void *priv)
1395{
1396	int err;
1397
1398	devl_lock(devlink);
1399	err = devl_traps_register(devlink, traps, traps_count, priv);
1400	devl_unlock(devlink);
1401	return err;
1402}
1403EXPORT_SYMBOL_GPL(devlink_traps_register);
1404
1405/**
1406 * devl_traps_unregister - Unregister packet traps from devlink.
1407 * @devlink: devlink.
1408 * @traps: Packet traps.
1409 * @traps_count: Count of provided packet traps.
1410 */
1411void devl_traps_unregister(struct devlink *devlink,
1412			   const struct devlink_trap *traps,
1413			   size_t traps_count)
1414{
1415	int i;
1416
1417	devl_assert_locked(devlink);
1418	/* Make sure we do not have any packets in-flight while unregistering
1419	 * traps by disabling all of them and waiting for a grace period.
1420	 */
1421	for (i = traps_count - 1; i >= 0; i--)
1422		devlink_trap_disable(devlink, &traps[i]);
1423	synchronize_rcu();
1424	for (i = traps_count - 1; i >= 0; i--)
1425		devlink_trap_unregister(devlink, &traps[i]);
1426}
1427EXPORT_SYMBOL_GPL(devl_traps_unregister);
1428
1429/**
1430 * devlink_traps_unregister - Unregister packet traps from devlink.
1431 * @devlink: devlink.
1432 * @traps: Packet traps.
1433 * @traps_count: Count of provided packet traps.
1434 *
1435 * Context: Takes and release devlink->lock <mutex>.
1436 */
1437void devlink_traps_unregister(struct devlink *devlink,
1438			      const struct devlink_trap *traps,
1439			      size_t traps_count)
1440{
1441	devl_lock(devlink);
1442	devl_traps_unregister(devlink, traps, traps_count);
1443	devl_unlock(devlink);
1444}
1445EXPORT_SYMBOL_GPL(devlink_traps_unregister);
1446
1447static void
1448devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
1449			  size_t skb_len)
1450{
1451	struct devlink_stats *stats;
1452
1453	stats = this_cpu_ptr(trap_stats);
1454	u64_stats_update_begin(&stats->syncp);
1455	u64_stats_add(&stats->rx_bytes, skb_len);
1456	u64_stats_inc(&stats->rx_packets);
1457	u64_stats_update_end(&stats->syncp);
1458}
1459
1460static void
1461devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
1462				 const struct devlink_trap_item *trap_item,
1463				 struct devlink_port *in_devlink_port,
1464				 const struct flow_action_cookie *fa_cookie)
1465{
1466	metadata->trap_name = trap_item->trap->name;
1467	metadata->trap_group_name = trap_item->group_item->group->name;
1468	metadata->fa_cookie = fa_cookie;
1469	metadata->trap_type = trap_item->trap->type;
1470
1471	spin_lock(&in_devlink_port->type_lock);
1472	if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
1473		metadata->input_dev = in_devlink_port->type_eth.netdev;
1474	spin_unlock(&in_devlink_port->type_lock);
1475}
1476
1477/**
1478 * devlink_trap_report - Report trapped packet to drop monitor.
1479 * @devlink: devlink.
1480 * @skb: Trapped packet.
1481 * @trap_ctx: Trap context.
1482 * @in_devlink_port: Input devlink port.
1483 * @fa_cookie: Flow action cookie. Could be NULL.
1484 */
1485void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
1486			 void *trap_ctx, struct devlink_port *in_devlink_port,
1487			 const struct flow_action_cookie *fa_cookie)
1488
1489{
1490	struct devlink_trap_item *trap_item = trap_ctx;
1491
1492	devlink_trap_stats_update(trap_item->stats, skb->len);
1493	devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
1494
1495	if (tracepoint_enabled(devlink_trap_report)) {
1496		struct devlink_trap_metadata metadata = {};
1497
1498		devlink_trap_report_metadata_set(&metadata, trap_item,
1499						 in_devlink_port, fa_cookie);
1500		trace_devlink_trap_report(devlink, skb, &metadata);
1501	}
1502}
1503EXPORT_SYMBOL_GPL(devlink_trap_report);
1504
1505/**
1506 * devlink_trap_ctx_priv - Trap context to driver private information.
1507 * @trap_ctx: Trap context.
1508 *
1509 * Return: Driver private information passed during registration.
1510 */
1511void *devlink_trap_ctx_priv(void *trap_ctx)
1512{
1513	struct devlink_trap_item *trap_item = trap_ctx;
1514
1515	return trap_item->priv;
1516}
1517EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
1518
1519static int
1520devlink_trap_group_item_policer_link(struct devlink *devlink,
1521				     struct devlink_trap_group_item *group_item)
1522{
1523	u32 policer_id = group_item->group->init_policer_id;
1524	struct devlink_trap_policer_item *policer_item;
1525
1526	if (policer_id == 0)
1527		return 0;
1528
1529	policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
1530	if (WARN_ON_ONCE(!policer_item))
1531		return -EINVAL;
1532
1533	group_item->policer_item = policer_item;
1534
1535	return 0;
1536}
1537
1538static int
1539devlink_trap_group_register(struct devlink *devlink,
1540			    const struct devlink_trap_group *group)
1541{
1542	struct devlink_trap_group_item *group_item;
1543	int err;
1544
1545	if (devlink_trap_group_item_lookup(devlink, group->name))
1546		return -EEXIST;
1547
1548	group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
1549	if (!group_item)
1550		return -ENOMEM;
1551
1552	group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
1553	if (!group_item->stats) {
1554		err = -ENOMEM;
1555		goto err_stats_alloc;
1556	}
1557
1558	group_item->group = group;
1559
1560	err = devlink_trap_group_item_policer_link(devlink, group_item);
1561	if (err)
1562		goto err_policer_link;
1563
1564	if (devlink->ops->trap_group_init) {
1565		err = devlink->ops->trap_group_init(devlink, group);
1566		if (err)
1567			goto err_group_init;
1568	}
1569
1570	list_add_tail(&group_item->list, &devlink->trap_group_list);
1571	devlink_trap_group_notify(devlink, group_item,
1572				  DEVLINK_CMD_TRAP_GROUP_NEW);
1573
1574	return 0;
1575
1576err_group_init:
1577err_policer_link:
1578	free_percpu(group_item->stats);
1579err_stats_alloc:
1580	kfree(group_item);
1581	return err;
1582}
1583
1584static void
1585devlink_trap_group_unregister(struct devlink *devlink,
1586			      const struct devlink_trap_group *group)
1587{
1588	struct devlink_trap_group_item *group_item;
1589
1590	group_item = devlink_trap_group_item_lookup(devlink, group->name);
1591	if (WARN_ON_ONCE(!group_item))
1592		return;
1593
1594	devlink_trap_group_notify(devlink, group_item,
1595				  DEVLINK_CMD_TRAP_GROUP_DEL);
1596	list_del(&group_item->list);
1597	free_percpu(group_item->stats);
1598	kfree(group_item);
1599}
1600
1601/**
1602 * devl_trap_groups_register - Register packet trap groups with devlink.
1603 * @devlink: devlink.
1604 * @groups: Packet trap groups.
1605 * @groups_count: Count of provided packet trap groups.
1606 *
1607 * Return: Non-zero value on failure.
1608 */
1609int devl_trap_groups_register(struct devlink *devlink,
1610			      const struct devlink_trap_group *groups,
1611			      size_t groups_count)
1612{
1613	int i, err;
1614
1615	devl_assert_locked(devlink);
1616	for (i = 0; i < groups_count; i++) {
1617		const struct devlink_trap_group *group = &groups[i];
1618
1619		err = devlink_trap_group_verify(group);
1620		if (err)
1621			goto err_trap_group_verify;
1622
1623		err = devlink_trap_group_register(devlink, group);
1624		if (err)
1625			goto err_trap_group_register;
1626	}
1627
1628	return 0;
1629
1630err_trap_group_register:
1631err_trap_group_verify:
1632	for (i--; i >= 0; i--)
1633		devlink_trap_group_unregister(devlink, &groups[i]);
1634	return err;
1635}
1636EXPORT_SYMBOL_GPL(devl_trap_groups_register);
1637
1638/**
1639 * devlink_trap_groups_register - Register packet trap groups with devlink.
1640 * @devlink: devlink.
1641 * @groups: Packet trap groups.
1642 * @groups_count: Count of provided packet trap groups.
1643 *
1644 * Context: Takes and release devlink->lock <mutex>.
1645 *
1646 * Return: Non-zero value on failure.
1647 */
1648int devlink_trap_groups_register(struct devlink *devlink,
1649				 const struct devlink_trap_group *groups,
1650				 size_t groups_count)
1651{
1652	int err;
1653
1654	devl_lock(devlink);
1655	err = devl_trap_groups_register(devlink, groups, groups_count);
1656	devl_unlock(devlink);
1657	return err;
1658}
1659EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
1660
1661/**
1662 * devl_trap_groups_unregister - Unregister packet trap groups from devlink.
1663 * @devlink: devlink.
1664 * @groups: Packet trap groups.
1665 * @groups_count: Count of provided packet trap groups.
1666 */
1667void devl_trap_groups_unregister(struct devlink *devlink,
1668				 const struct devlink_trap_group *groups,
1669				 size_t groups_count)
1670{
1671	int i;
1672
1673	devl_assert_locked(devlink);
1674	for (i = groups_count - 1; i >= 0; i--)
1675		devlink_trap_group_unregister(devlink, &groups[i]);
1676}
1677EXPORT_SYMBOL_GPL(devl_trap_groups_unregister);
1678
1679/**
1680 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
1681 * @devlink: devlink.
1682 * @groups: Packet trap groups.
1683 * @groups_count: Count of provided packet trap groups.
1684 *
1685 * Context: Takes and release devlink->lock <mutex>.
1686 */
1687void devlink_trap_groups_unregister(struct devlink *devlink,
1688				    const struct devlink_trap_group *groups,
1689				    size_t groups_count)
1690{
1691	devl_lock(devlink);
1692	devl_trap_groups_unregister(devlink, groups, groups_count);
1693	devl_unlock(devlink);
1694}
1695EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
1696
1697static void
1698devlink_trap_policer_notify(struct devlink *devlink,
1699			    const struct devlink_trap_policer_item *policer_item,
1700			    enum devlink_command cmd)
1701{
1702	struct sk_buff *msg;
1703	int err;
1704
1705	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
1706		     cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
1707
1708	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
1709		return;
1710
1711	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1712	if (!msg)
1713		return;
1714
1715	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
1716					   0, 0);
1717	if (err) {
1718		nlmsg_free(msg);
1719		return;
1720	}
1721
1722	devlink_nl_notify_send(devlink, msg);
1723}
1724
1725void devlink_trap_policers_notify_register(struct devlink *devlink)
1726{
1727	struct devlink_trap_policer_item *policer_item;
1728
1729	list_for_each_entry(policer_item, &devlink->trap_policer_list, list)
1730		devlink_trap_policer_notify(devlink, policer_item,
1731					    DEVLINK_CMD_TRAP_POLICER_NEW);
1732}
1733
1734void devlink_trap_policers_notify_unregister(struct devlink *devlink)
1735{
1736	struct devlink_trap_policer_item *policer_item;
1737
1738	list_for_each_entry_reverse(policer_item, &devlink->trap_policer_list,
1739				    list)
1740		devlink_trap_policer_notify(devlink, policer_item,
1741					    DEVLINK_CMD_TRAP_POLICER_DEL);
1742}
1743
1744static int
1745devlink_trap_policer_register(struct devlink *devlink,
1746			      const struct devlink_trap_policer *policer)
1747{
1748	struct devlink_trap_policer_item *policer_item;
1749	int err;
1750
1751	if (devlink_trap_policer_item_lookup(devlink, policer->id))
1752		return -EEXIST;
1753
1754	policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
1755	if (!policer_item)
1756		return -ENOMEM;
1757
1758	policer_item->policer = policer;
1759	policer_item->rate = policer->init_rate;
1760	policer_item->burst = policer->init_burst;
1761
1762	if (devlink->ops->trap_policer_init) {
1763		err = devlink->ops->trap_policer_init(devlink, policer);
1764		if (err)
1765			goto err_policer_init;
1766	}
1767
1768	list_add_tail(&policer_item->list, &devlink->trap_policer_list);
1769	devlink_trap_policer_notify(devlink, policer_item,
1770				    DEVLINK_CMD_TRAP_POLICER_NEW);
1771
1772	return 0;
1773
1774err_policer_init:
1775	kfree(policer_item);
1776	return err;
1777}
1778
1779static void
1780devlink_trap_policer_unregister(struct devlink *devlink,
1781				const struct devlink_trap_policer *policer)
1782{
1783	struct devlink_trap_policer_item *policer_item;
1784
1785	policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
1786	if (WARN_ON_ONCE(!policer_item))
1787		return;
1788
1789	devlink_trap_policer_notify(devlink, policer_item,
1790				    DEVLINK_CMD_TRAP_POLICER_DEL);
1791	list_del(&policer_item->list);
1792	if (devlink->ops->trap_policer_fini)
1793		devlink->ops->trap_policer_fini(devlink, policer);
1794	kfree(policer_item);
1795}
1796
1797/**
1798 * devl_trap_policers_register - Register packet trap policers with devlink.
1799 * @devlink: devlink.
1800 * @policers: Packet trap policers.
1801 * @policers_count: Count of provided packet trap policers.
1802 *
1803 * Return: Non-zero value on failure.
1804 */
1805int
1806devl_trap_policers_register(struct devlink *devlink,
1807			    const struct devlink_trap_policer *policers,
1808			    size_t policers_count)
1809{
1810	int i, err;
1811
1812	devl_assert_locked(devlink);
1813	for (i = 0; i < policers_count; i++) {
1814		const struct devlink_trap_policer *policer = &policers[i];
1815
1816		if (WARN_ON(policer->id == 0 ||
1817			    policer->max_rate < policer->min_rate ||
1818			    policer->max_burst < policer->min_burst)) {
1819			err = -EINVAL;
1820			goto err_trap_policer_verify;
1821		}
1822
1823		err = devlink_trap_policer_register(devlink, policer);
1824		if (err)
1825			goto err_trap_policer_register;
1826	}
1827	return 0;
1828
1829err_trap_policer_register:
1830err_trap_policer_verify:
1831	for (i--; i >= 0; i--)
1832		devlink_trap_policer_unregister(devlink, &policers[i]);
1833	return err;
1834}
1835EXPORT_SYMBOL_GPL(devl_trap_policers_register);
1836
1837/**
1838 * devl_trap_policers_unregister - Unregister packet trap policers from devlink.
1839 * @devlink: devlink.
1840 * @policers: Packet trap policers.
1841 * @policers_count: Count of provided packet trap policers.
1842 */
1843void
1844devl_trap_policers_unregister(struct devlink *devlink,
1845			      const struct devlink_trap_policer *policers,
1846			      size_t policers_count)
1847{
1848	int i;
1849
1850	devl_assert_locked(devlink);
1851	for (i = policers_count - 1; i >= 0; i--)
1852		devlink_trap_policer_unregister(devlink, &policers[i]);
1853}
1854EXPORT_SYMBOL_GPL(devl_trap_policers_unregister);