0001
0002
0003
0004 #include <linux/bitops.h>
0005 #include <linux/kernel.h>
0006 #include <linux/netlink.h>
0007 #include <net/devlink.h>
0008 #include <uapi/linux/devlink.h>
0009
0010 #include "core.h"
0011 #include "reg.h"
0012 #include "spectrum.h"
0013 #include "spectrum_trap.h"
0014
0015 struct mlxsw_sp_trap_policer_item {
0016 struct devlink_trap_policer policer;
0017 u16 hw_id;
0018 };
0019
0020 struct mlxsw_sp_trap_group_item {
0021 struct devlink_trap_group group;
0022 u16 hw_group_id;
0023 u8 priority;
0024 u8 fixed_policer:1;
0025 };
0026
0027 #define MLXSW_SP_TRAP_LISTENERS_MAX 3
0028
0029 struct mlxsw_sp_trap_item {
0030 struct devlink_trap trap;
0031 struct mlxsw_listener listeners_arr[MLXSW_SP_TRAP_LISTENERS_MAX];
0032 u8 is_source:1;
0033 };
0034
0035
0036
0037
0038 enum {
0039 DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
0040 DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
0041 DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
0042 };
0043
0044 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
0045 "irif_disabled"
0046 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
0047 "erif_disabled"
0048
0049 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
0050
0051 enum {
0052
0053 MLXSW_SP_MIRROR_REASON_INGRESS = 1,
0054
0055 MLXSW_SP_MIRROR_REASON_POLICY_ENGINE = 2,
0056
0057 MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9,
0058
0059 MLXSW_SP_MIRROR_REASON_EGRESS = 14,
0060 };
0061
0062 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
0063 u16 local_port,
0064 struct mlxsw_sp_port *mlxsw_sp_port)
0065 {
0066 struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
0067
0068 if (unlikely(!mlxsw_sp_port)) {
0069 dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
0070 local_port);
0071 kfree_skb(skb);
0072 return -EINVAL;
0073 }
0074
0075 skb->dev = mlxsw_sp_port->dev;
0076
0077 pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
0078 u64_stats_update_begin(&pcpu_stats->syncp);
0079 pcpu_stats->rx_packets++;
0080 pcpu_stats->rx_bytes += skb->len;
0081 u64_stats_update_end(&pcpu_stats->syncp);
0082
0083 skb->protocol = eth_type_trans(skb, skb->dev);
0084
0085 return 0;
0086 }
0087
0088 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u16 local_port,
0089 void *trap_ctx)
0090 {
0091 struct devlink_port *in_devlink_port;
0092 struct mlxsw_sp_port *mlxsw_sp_port;
0093 struct mlxsw_sp *mlxsw_sp;
0094 struct devlink *devlink;
0095 int err;
0096
0097 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0098 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0099
0100 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0101 if (err)
0102 return;
0103
0104 devlink = priv_to_devlink(mlxsw_sp->core);
0105 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0106 local_port);
0107 skb_push(skb, ETH_HLEN);
0108 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
0109 consume_skb(skb);
0110 }
0111
0112 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u16 local_port,
0113 void *trap_ctx)
0114 {
0115 u32 cookie_index = mlxsw_skb_cb(skb)->rx_md_info.cookie_index;
0116 const struct flow_action_cookie *fa_cookie;
0117 struct devlink_port *in_devlink_port;
0118 struct mlxsw_sp_port *mlxsw_sp_port;
0119 struct mlxsw_sp *mlxsw_sp;
0120 struct devlink *devlink;
0121 int err;
0122
0123 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0124 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0125
0126 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0127 if (err)
0128 return;
0129
0130 devlink = priv_to_devlink(mlxsw_sp->core);
0131 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0132 local_port);
0133 skb_push(skb, ETH_HLEN);
0134 rcu_read_lock();
0135 fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index);
0136 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie);
0137 rcu_read_unlock();
0138 consume_skb(skb);
0139 }
0140
0141 static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
0142 void *trap_ctx)
0143 {
0144 struct devlink_port *in_devlink_port;
0145 struct mlxsw_sp_port *mlxsw_sp_port;
0146 struct mlxsw_sp *mlxsw_sp;
0147 struct devlink *devlink;
0148 int err;
0149
0150 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0151 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0152
0153 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0154 if (err)
0155 return err;
0156
0157 devlink = priv_to_devlink(mlxsw_sp->core);
0158 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0159 local_port);
0160 skb_push(skb, ETH_HLEN);
0161 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
0162 skb_pull(skb, ETH_HLEN);
0163
0164 return 0;
0165 }
0166
0167 static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
0168 void *trap_ctx)
0169 {
0170 int err;
0171
0172 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0173 if (err)
0174 return;
0175
0176 netif_receive_skb(skb);
0177 }
0178
0179 static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u16 local_port,
0180 void *trap_ctx)
0181 {
0182 skb->offload_fwd_mark = 1;
0183 mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0184 }
0185
0186 static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u16 local_port,
0187 void *trap_ctx)
0188 {
0189 skb->offload_l3_fwd_mark = 1;
0190 skb->offload_fwd_mark = 1;
0191 mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0192 }
0193
0194 static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u16 local_port,
0195 void *trap_ctx)
0196 {
0197 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0198 int err;
0199
0200 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0201 if (err)
0202 return;
0203
0204
0205
0206
0207 skb_push(skb, ETH_HLEN);
0208 mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port);
0209 }
0210
0211 static struct mlxsw_sp_port *
0212 mlxsw_sp_sample_tx_port_get(struct mlxsw_sp *mlxsw_sp,
0213 const struct mlxsw_rx_md_info *rx_md_info)
0214 {
0215 u16 local_port;
0216
0217 if (!rx_md_info->tx_port_valid)
0218 return NULL;
0219
0220 if (rx_md_info->tx_port_is_lag)
0221 local_port = mlxsw_core_lag_mapping_get(mlxsw_sp->core,
0222 rx_md_info->tx_lag_id,
0223 rx_md_info->tx_lag_port_index);
0224 else
0225 local_port = rx_md_info->tx_sys_port;
0226
0227 if (local_port >= mlxsw_core_max_ports(mlxsw_sp->core))
0228 return NULL;
0229
0230 return mlxsw_sp->ports[local_port];
0231 }
0232
0233
0234
0235
0236 #define MLXSW_SP_MIRROR_LATENCY_SHIFT 6
0237
0238 static void mlxsw_sp_psample_md_init(struct mlxsw_sp *mlxsw_sp,
0239 struct psample_metadata *md,
0240 struct sk_buff *skb, int in_ifindex,
0241 bool truncate, u32 trunc_size)
0242 {
0243 struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
0244 struct mlxsw_sp_port *mlxsw_sp_port;
0245
0246 md->trunc_size = truncate ? trunc_size : skb->len;
0247 md->in_ifindex = in_ifindex;
0248 mlxsw_sp_port = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
0249 md->out_ifindex = mlxsw_sp_port && mlxsw_sp_port->dev ?
0250 mlxsw_sp_port->dev->ifindex : 0;
0251 md->out_tc_valid = rx_md_info->tx_tc_valid;
0252 md->out_tc = rx_md_info->tx_tc;
0253 md->out_tc_occ_valid = rx_md_info->tx_congestion_valid;
0254 md->out_tc_occ = rx_md_info->tx_congestion;
0255 md->latency_valid = rx_md_info->latency_valid;
0256 md->latency = rx_md_info->latency;
0257 md->latency <<= MLXSW_SP_MIRROR_LATENCY_SHIFT;
0258 }
0259
0260 static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u16 local_port,
0261 void *trap_ctx)
0262 {
0263 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0264 struct mlxsw_sp_sample_trigger trigger;
0265 struct mlxsw_sp_sample_params *params;
0266 struct mlxsw_sp_port *mlxsw_sp_port;
0267 struct psample_metadata md = {};
0268 int err;
0269
0270 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0271 if (err)
0272 return;
0273
0274 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0275 if (!mlxsw_sp_port)
0276 goto out;
0277
0278 trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS;
0279 trigger.local_port = local_port;
0280 params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0281 if (!params)
0282 goto out;
0283
0284
0285
0286
0287 skb_push(skb, ETH_HLEN);
0288 mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0289 mlxsw_sp_port->dev->ifindex, params->truncate,
0290 params->trunc_size);
0291 psample_sample_packet(params->psample_group, skb, params->rate, &md);
0292 out:
0293 consume_skb(skb);
0294 }
0295
0296 static void mlxsw_sp_rx_sample_tx_listener(struct sk_buff *skb, u16 local_port,
0297 void *trap_ctx)
0298 {
0299 struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
0300 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0301 struct mlxsw_sp_port *mlxsw_sp_port, *mlxsw_sp_port_tx;
0302 struct mlxsw_sp_sample_trigger trigger;
0303 struct mlxsw_sp_sample_params *params;
0304 struct psample_metadata md = {};
0305 int err;
0306
0307
0308
0309
0310 if (local_port == MLXSW_PORT_CPU_PORT)
0311 goto out;
0312
0313 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0314 if (err)
0315 return;
0316
0317 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0318 if (!mlxsw_sp_port)
0319 goto out;
0320
0321
0322
0323
0324 mlxsw_sp_port_tx = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
0325 if (!mlxsw_sp_port_tx)
0326 goto out;
0327
0328 trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS;
0329 trigger.local_port = mlxsw_sp_port_tx->local_port;
0330 params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0331 if (!params)
0332 goto out;
0333
0334
0335
0336
0337 skb_push(skb, ETH_HLEN);
0338 mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0339 mlxsw_sp_port->dev->ifindex, params->truncate,
0340 params->trunc_size);
0341 psample_sample_packet(params->psample_group, skb, params->rate, &md);
0342 out:
0343 consume_skb(skb);
0344 }
0345
0346 static void mlxsw_sp_rx_sample_acl_listener(struct sk_buff *skb, u16 local_port,
0347 void *trap_ctx)
0348 {
0349 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0350 struct mlxsw_sp_sample_trigger trigger = {
0351 .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE,
0352 };
0353 struct mlxsw_sp_sample_params *params;
0354 struct mlxsw_sp_port *mlxsw_sp_port;
0355 struct psample_metadata md = {};
0356 int err;
0357
0358 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0359 if (err)
0360 return;
0361
0362 mlxsw_sp_port = mlxsw_sp->ports[local_port];
0363 if (!mlxsw_sp_port)
0364 goto out;
0365
0366 params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0367 if (!params)
0368 goto out;
0369
0370
0371
0372
0373 skb_push(skb, ETH_HLEN);
0374 mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0375 mlxsw_sp_port->dev->ifindex, params->truncate,
0376 params->trunc_size);
0377 psample_sample_packet(params->psample_group, skb, params->rate, &md);
0378 out:
0379 consume_skb(skb);
0380 }
0381
0382 #define MLXSW_SP_TRAP_DROP(_id, _group_id) \
0383 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
0384 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
0385 MLXSW_SP_TRAP_METADATA)
0386
0387 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata) \
0388 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
0389 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
0390 MLXSW_SP_TRAP_METADATA | (_metadata))
0391
0392 #define MLXSW_SP_TRAP_BUFFER_DROP(_id) \
0393 DEVLINK_TRAP_GENERIC(DROP, TRAP, _id, \
0394 DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS, \
0395 MLXSW_SP_TRAP_METADATA)
0396
0397 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \
0398 DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \
0399 DEVLINK_MLXSW_TRAP_NAME_##_id, \
0400 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
0401 MLXSW_SP_TRAP_METADATA)
0402
0403 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \
0404 DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
0405 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
0406 MLXSW_SP_TRAP_METADATA)
0407
0408 #define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action) \
0409 DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \
0410 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
0411 MLXSW_SP_TRAP_METADATA)
0412
0413 #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \
0414 MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \
0415 TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \
0416 SET_FW_DEFAULT, SP_##_group_id)
0417
0418 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id) \
0419 MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id, \
0420 TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id, \
0421 SET_FW_DEFAULT, SP_##_dis_group_id)
0422
0423 #define MLXSW_SP_RXL_BUFFER_DISCARD(_mirror_reason) \
0424 MLXSW_RXL_MIRROR(mlxsw_sp_rx_drop_listener, 0, SP_BUFFER_DISCARDS, \
0425 MLXSW_SP_MIRROR_REASON_##_mirror_reason)
0426
0427 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \
0428 MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, \
0429 _action, false, SP_##_group_id, SET_FW_DEFAULT)
0430
0431 #define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl) \
0432 MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action, \
0433 _is_ctrl, SP_##_group_id, DISCARD)
0434
0435 #define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl) \
0436 MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl, \
0437 SP_##_group_id, DISCARD)
0438
0439 #define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl) \
0440 MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl, \
0441 SP_##_group_id, DISCARD)
0442
0443 #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst) \
0444 DEVLINK_TRAP_POLICER(_id, _rate, _burst, \
0445 MLXSW_REG_QPCR_HIGHEST_CIR, \
0446 MLXSW_REG_QPCR_LOWEST_CIR, \
0447 1 << MLXSW_REG_QPCR_HIGHEST_CBS, \
0448 1 << MLXSW_REG_QPCR_LOWEST_CBS)
0449
0450
0451 static const struct mlxsw_sp_trap_policer_item
0452 mlxsw_sp_trap_policer_items_arr[] = {
0453 {
0454 .policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 4096),
0455 },
0456 {
0457 .policer = MLXSW_SP_TRAP_POLICER(2, 128, 128),
0458 },
0459 {
0460 .policer = MLXSW_SP_TRAP_POLICER(3, 128, 128),
0461 },
0462 {
0463 .policer = MLXSW_SP_TRAP_POLICER(4, 128, 128),
0464 },
0465 {
0466 .policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 8192),
0467 },
0468 {
0469 .policer = MLXSW_SP_TRAP_POLICER(6, 128, 128),
0470 },
0471 {
0472 .policer = MLXSW_SP_TRAP_POLICER(7, 1024, 512),
0473 },
0474 {
0475 .policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 8192),
0476 },
0477 {
0478 .policer = MLXSW_SP_TRAP_POLICER(9, 128, 128),
0479 },
0480 {
0481 .policer = MLXSW_SP_TRAP_POLICER(10, 1024, 512),
0482 },
0483 {
0484 .policer = MLXSW_SP_TRAP_POLICER(11, 256, 128),
0485 },
0486 {
0487 .policer = MLXSW_SP_TRAP_POLICER(12, 128, 128),
0488 },
0489 {
0490 .policer = MLXSW_SP_TRAP_POLICER(13, 128, 128),
0491 },
0492 {
0493 .policer = MLXSW_SP_TRAP_POLICER(14, 1024, 512),
0494 },
0495 {
0496 .policer = MLXSW_SP_TRAP_POLICER(15, 1024, 512),
0497 },
0498 {
0499 .policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 16384),
0500 },
0501 {
0502 .policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 8192),
0503 },
0504 {
0505 .policer = MLXSW_SP_TRAP_POLICER(18, 1024, 512),
0506 },
0507 {
0508 .policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512),
0509 },
0510 {
0511 .policer = MLXSW_SP_TRAP_POLICER(20, 10240, 4096),
0512 },
0513 };
0514
0515 static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
0516 {
0517 .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),
0518 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,
0519 .priority = 0,
0520 },
0521 {
0522 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
0523 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,
0524 .priority = 0,
0525 },
0526 {
0527 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),
0528 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,
0529 .priority = 2,
0530 },
0531 {
0532 .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),
0533 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
0534 .priority = 0,
0535 },
0536 {
0537 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),
0538 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
0539 .priority = 0,
0540 },
0541 {
0542 .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2),
0543 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,
0544 .priority = 5,
0545 },
0546 {
0547 .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3),
0548 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,
0549 .priority = 5,
0550 },
0551 {
0552 .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4),
0553 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,
0554 .priority = 5,
0555 },
0556 {
0557 .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5),
0558 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING,
0559 .priority = 3,
0560 },
0561 {
0562 .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6),
0563 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP,
0564 .priority = 2,
0565 },
0566 {
0567 .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7),
0568 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY,
0569 .priority = 2,
0570 },
0571 {
0572 .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8),
0573 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD,
0574 .priority = 5,
0575 },
0576 {
0577 .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9),
0578 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF,
0579 .priority = 5,
0580 },
0581 {
0582 .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10),
0583 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP,
0584 .priority = 4,
0585 },
0586 {
0587 .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11),
0588 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,
0589 .priority = 5,
0590 },
0591 {
0592 .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12),
0593 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM,
0594 .priority = 5,
0595 },
0596 {
0597 .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13),
0598 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
0599 .priority = 0,
0600 },
0601 {
0602 .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14),
0603 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME,
0604 .priority = 2,
0605 },
0606 {
0607 .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19),
0608 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE,
0609 .priority = 1,
0610 },
0611 {
0612 .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15),
0613 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6,
0614 .priority = 2,
0615 },
0616 {
0617 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16),
0618 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
0619 .priority = 5,
0620 },
0621 {
0622 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17),
0623 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
0624 .priority = 2,
0625 },
0626 {
0627 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18),
0628 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,
0629 .priority = 4,
0630 },
0631 };
0632
0633 static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
0634 {
0635 .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
0636 .listeners_arr = {
0637 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
0638 },
0639 },
0640 {
0641 .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
0642 .listeners_arr = {
0643 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW,
0644 L2_DISCARDS),
0645 },
0646 },
0647 {
0648 .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
0649 .listeners_arr = {
0650 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
0651 },
0652 },
0653 {
0654 .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
0655 .listeners_arr = {
0656 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
0657 },
0658 },
0659 {
0660 .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
0661 .listeners_arr = {
0662 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
0663 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
0664 },
0665 },
0666 {
0667 .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
0668 .listeners_arr = {
0669 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
0670 },
0671 },
0672 {
0673 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
0674 .listeners_arr = {
0675 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
0676 },
0677 },
0678 {
0679 .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
0680 .listeners_arr = {
0681 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET,
0682 L3_DISCARDS),
0683 },
0684 },
0685 {
0686 .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
0687 .listeners_arr = {
0688 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC,
0689 L3_DISCARDS),
0690 },
0691 },
0692 {
0693 .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
0694 .listeners_arr = {
0695 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
0696 },
0697 },
0698 {
0699 .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
0700 .listeners_arr = {
0701 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
0702 },
0703 },
0704 {
0705 .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
0706 .listeners_arr = {
0707 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
0708 },
0709 },
0710 {
0711 .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
0712 .listeners_arr = {
0713 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR,
0714 L3_DISCARDS),
0715 },
0716 },
0717 {
0718 .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
0719 .listeners_arr = {
0720 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC,
0721 L3_DISCARDS),
0722 },
0723 },
0724 {
0725 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE,
0726 L3_DROPS),
0727 .listeners_arr = {
0728 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE,
0729 L3_DISCARDS),
0730 },
0731 },
0732 {
0733 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
0734 L3_DROPS),
0735 .listeners_arr = {
0736 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
0737 L3_DISCARDS),
0738 },
0739 },
0740 {
0741 .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
0742 .listeners_arr = {
0743 MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS,
0744 TRAP_TO_CPU),
0745 },
0746 },
0747 {
0748 .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
0749 .listeners_arr = {
0750 MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS,
0751 TRAP_TO_CPU),
0752 },
0753 },
0754 {
0755 .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS),
0756 .listeners_arr = {
0757 MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU),
0758 },
0759 },
0760 {
0761 .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS),
0762 .listeners_arr = {
0763 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS,
0764 TRAP_TO_CPU),
0765 },
0766 },
0767 {
0768 .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH,
0769 L3_EXCEPTIONS),
0770 .listeners_arr = {
0771 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS,
0772 TRAP_TO_CPU),
0773 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS,
0774 TRAP_TO_CPU),
0775 MLXSW_SP_RXL_EXCEPTION(RTR_EGRESS0, L3_EXCEPTIONS,
0776 TRAP_EXCEPTION_TO_CPU),
0777 },
0778 },
0779 {
0780 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS,
0781 L3_EXCEPTIONS),
0782 .listeners_arr = {
0783 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4,
0784 L3_EXCEPTIONS,
0785 TRAP_EXCEPTION_TO_CPU),
0786 },
0787 },
0788 {
0789 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS,
0790 L3_EXCEPTIONS),
0791 .listeners_arr = {
0792 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6,
0793 L3_EXCEPTIONS,
0794 TRAP_EXCEPTION_TO_CPU),
0795 },
0796 },
0797 {
0798 .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
0799 .listeners_arr = {
0800 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
0801 },
0802 },
0803 {
0804 .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
0805 .listeners_arr = {
0806 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
0807 },
0808 },
0809 {
0810 .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
0811 .listeners_arr = {
0812 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
0813 },
0814 },
0815 {
0816 .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),
0817 .listeners_arr = {
0818 MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,
0819 TRAP_EXCEPTION_TO_CPU),
0820 MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR,
0821 TUNNEL_DISCARDS,
0822 TRAP_EXCEPTION_TO_CPU),
0823 MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,
0824 TRAP_EXCEPTION_TO_CPU),
0825 },
0826 },
0827 {
0828 .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),
0829 .listeners_arr = {
0830 MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),
0831 },
0832 },
0833 {
0834 .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP,
0835 ACL_DROPS,
0836 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
0837 .listeners_arr = {
0838 MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS,
0839 DUMMY),
0840 },
0841 },
0842 {
0843 .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP,
0844 ACL_DROPS,
0845 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
0846 .listeners_arr = {
0847 MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS,
0848 DUMMY),
0849 },
0850 },
0851 {
0852 .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP),
0853 .listeners_arr = {
0854 MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true),
0855 },
0856 },
0857 {
0858 .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP),
0859 .listeners_arr = {
0860 MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true),
0861 },
0862 },
0863 {
0864 .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP),
0865 .listeners_arr = {
0866 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU,
0867 true, SP_LLDP, DISCARD),
0868 },
0869 },
0870 {
0871 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),
0872 .listeners_arr = {
0873 MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING,
0874 MIRROR_TO_CPU, false),
0875 },
0876 },
0877 {
0878 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING,
0879 TRAP),
0880 .listeners_arr = {
0881 MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING,
0882 TRAP_TO_CPU, false),
0883 },
0884 },
0885 {
0886 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING,
0887 TRAP),
0888 .listeners_arr = {
0889 MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING,
0890 TRAP_TO_CPU, false),
0891 },
0892 },
0893 {
0894 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING,
0895 TRAP),
0896 .listeners_arr = {
0897 MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING,
0898 TRAP_TO_CPU, false),
0899 },
0900 },
0901 {
0902 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING,
0903 TRAP),
0904 .listeners_arr = {
0905 MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING,
0906 TRAP_TO_CPU, false),
0907 },
0908 },
0909 {
0910 .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR),
0911 .listeners_arr = {
0912 MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY,
0913 MC_SNOOPING, MIRROR_TO_CPU, false),
0914 },
0915 },
0916 {
0917 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING,
0918 TRAP),
0919 .listeners_arr = {
0920 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT,
0921 MC_SNOOPING, TRAP_TO_CPU, false),
0922 },
0923 },
0924 {
0925 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING,
0926 TRAP),
0927 .listeners_arr = {
0928 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT,
0929 MC_SNOOPING, TRAP_TO_CPU, false),
0930 },
0931 },
0932 {
0933 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING,
0934 TRAP),
0935 .listeners_arr = {
0936 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE,
0937 MC_SNOOPING, TRAP_TO_CPU, false),
0938 },
0939 },
0940 {
0941 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP),
0942 .listeners_arr = {
0943 MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false),
0944 },
0945 },
0946 {
0947 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP),
0948 .listeners_arr = {
0949 MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false),
0950 },
0951 },
0952 {
0953 .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,
0954 MIRROR),
0955 .listeners_arr = {
0956 MLXSW_SP_RXL_MARK(ROUTER_ARPBC, NEIGH_DISCOVERY,
0957 TRAP_TO_CPU, false),
0958 },
0959 },
0960 {
0961 .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
0962 MIRROR),
0963 .listeners_arr = {
0964 MLXSW_SP_RXL_MARK(ROUTER_ARPUC, NEIGH_DISCOVERY,
0965 TRAP_TO_CPU, false),
0966 },
0967 },
0968 {
0969 .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY,
0970 TRAP),
0971 .listeners_arr = {
0972 MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY,
0973 TRAP_TO_CPU, false),
0974 },
0975 },
0976 {
0977 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT,
0978 NEIGH_DISCOVERY, TRAP),
0979 .listeners_arr = {
0980 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION,
0981 NEIGH_DISCOVERY, TRAP_TO_CPU, false),
0982 },
0983 },
0984 {
0985 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT,
0986 NEIGH_DISCOVERY, TRAP),
0987 .listeners_arr = {
0988 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT,
0989 NEIGH_DISCOVERY, TRAP_TO_CPU, false),
0990 },
0991 },
0992 {
0993 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP),
0994 .listeners_arr = {
0995 MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false),
0996 },
0997 },
0998 {
0999 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP),
1000 .listeners_arr = {
1001 MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false),
1002 },
1003 },
1004 {
1005 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP),
1006 .listeners_arr = {
1007 MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false),
1008 },
1009 },
1010 {
1011 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP),
1012 .listeners_arr = {
1013 MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false),
1014 },
1015 },
1016 {
1017 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP),
1018 .listeners_arr = {
1019 MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false),
1020 },
1021 },
1022 {
1023 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP),
1024 .listeners_arr = {
1025 MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false),
1026 },
1027 },
1028 {
1029 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP),
1030 .listeners_arr = {
1031 MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false),
1032 },
1033 },
1034 {
1035 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP),
1036 .listeners_arr = {
1037 MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false),
1038 },
1039 },
1040 {
1041 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP),
1042 .listeners_arr = {
1043 MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false),
1044 },
1045 },
1046 {
1047 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP),
1048 .listeners_arr = {
1049 MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false),
1050 },
1051 },
1052 {
1053 .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR),
1054 .listeners_arr = {
1055 MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU,
1056 false),
1057 },
1058 },
1059 {
1060 .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
1061 TRAP),
1062 .listeners_arr = {
1063 MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false),
1064 },
1065 },
1066 {
1067 .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY,
1068 TRAP),
1069 .listeners_arr = {
1070 MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE,
1071 TRAP_TO_CPU, false),
1072 },
1073 },
1074 {
1075 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE,
1076 LOCAL_DELIVERY, TRAP),
1077 .listeners_arr = {
1078 MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME,
1079 TRAP_TO_CPU, false),
1080 },
1081 },
1082 {
1083 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY,
1084 TRAP),
1085 .listeners_arr = {
1086 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU,
1087 false),
1088 },
1089 },
1090 {
1091
1092
1093
1094 #undef IPV6_ROUTER_ALERT
1095 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY,
1096 TRAP),
1097 .listeners_arr = {
1098 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU,
1099 false),
1100 },
1101 },
1102 {
1103 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP),
1104 .listeners_arr = {
1105 MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6,
1106 TRAP_TO_CPU, false),
1107 },
1108 },
1109 {
1110 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP),
1111 .listeners_arr = {
1112 MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6,
1113 TRAP_TO_CPU, false),
1114 },
1115 },
1116 {
1117 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP),
1118 .listeners_arr = {
1119 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6,
1120 TRAP_TO_CPU, false),
1121 },
1122 },
1123 {
1124 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP),
1125 .listeners_arr = {
1126 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6,
1127 TRAP_TO_CPU, false),
1128 },
1129 },
1130 {
1131 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP),
1132 .listeners_arr = {
1133 MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6,
1134 TRAP_TO_CPU, false),
1135 },
1136 },
1137 {
1138 .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP),
1139 .listeners_arr = {
1140 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU,
1141 false, SP_PTP0, DISCARD),
1142 },
1143 },
1144 {
1145 .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP),
1146 .listeners_arr = {
1147 MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false),
1148 },
1149 },
1150 {
1151 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP),
1152 .listeners_arr = {
1153 MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU,
1154 false),
1155 },
1156 },
1157 {
1158 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_NEXTHOP, L3_DROPS),
1159 .listeners_arr = {
1160 MLXSW_SP_RXL_DISCARD(ROUTER3, L3_DISCARDS),
1161 },
1162 },
1163 };
1164
1165 static struct mlxsw_sp_trap_policer_item *
1166 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)
1167 {
1168 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1169 int i;
1170
1171 for (i = 0; i < trap->policers_count; i++) {
1172 if (trap->policer_items_arr[i].policer.id == id)
1173 return &trap->policer_items_arr[i];
1174 }
1175
1176 return NULL;
1177 }
1178
1179 static struct mlxsw_sp_trap_group_item *
1180 mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1181 {
1182 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1183 int i;
1184
1185 for (i = 0; i < trap->groups_count; i++) {
1186 if (trap->group_items_arr[i].group.id == id)
1187 return &trap->group_items_arr[i];
1188 }
1189
1190 return NULL;
1191 }
1192
1193 static struct mlxsw_sp_trap_item *
1194 mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1195 {
1196 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1197 int i;
1198
1199 for (i = 0; i < trap->traps_count; i++) {
1200 if (trap->trap_items_arr[i].trap.id == id)
1201 return &trap->trap_items_arr[i];
1202 }
1203
1204 return NULL;
1205 }
1206
1207 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp)
1208 {
1209 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1210 char qpcr_pl[MLXSW_REG_QPCR_LEN];
1211 u16 hw_id;
1212
1213
1214
1215
1216 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1217 if (WARN_ON(hw_id == trap->max_policers))
1218 return -ENOBUFS;
1219
1220 __set_bit(hw_id, trap->policers_usage);
1221 trap->thin_policer_hw_id = hw_id;
1222 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M,
1223 false, 1, 4);
1224 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1225 }
1226
1227 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp)
1228 {
1229 char htgt_pl[MLXSW_REG_HTGT_LEN];
1230
1231 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY,
1232 mlxsw_sp->trap->thin_policer_hw_id, 0, 1);
1233 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);
1234 }
1235
1236 static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1237 {
1238 size_t arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr);
1239 size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item);
1240 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1241 size_t free_policers = 0;
1242 u32 last_id;
1243 int i;
1244
1245 for_each_clear_bit(i, trap->policers_usage, trap->max_policers)
1246 free_policers++;
1247
1248 if (arr_size > free_policers) {
1249 dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n");
1250 return -ENOBUFS;
1251 }
1252
1253 trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL);
1254 if (!trap->policer_items_arr)
1255 return -ENOMEM;
1256
1257 trap->policers_count = free_policers;
1258
1259
1260 memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr,
1261 elem_size * arr_size);
1262
1263
1264
1265
1266 last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id;
1267 for (i = arr_size; i < trap->policers_count; i++) {
1268 const struct mlxsw_sp_trap_policer_item *policer_item;
1269
1270
1271
1272
1273 policer_item = &mlxsw_sp_trap_policer_items_arr[0];
1274 trap->policer_items_arr[i] = *policer_item;
1275 trap->policer_items_arr[i].policer.id = ++last_id;
1276 trap->policer_items_arr[i].policer.init_rate = 1;
1277 trap->policer_items_arr[i].policer.init_burst = 16;
1278 }
1279
1280 return 0;
1281 }
1282
1283 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1284 {
1285 kfree(mlxsw_sp->trap->policer_items_arr);
1286 }
1287
1288 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp)
1289 {
1290 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1291 const struct mlxsw_sp_trap_policer_item *policer_item;
1292 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1293 int err, i;
1294
1295 err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp);
1296 if (err)
1297 return err;
1298
1299 for (i = 0; i < trap->policers_count; i++) {
1300 policer_item = &trap->policer_items_arr[i];
1301 err = devl_trap_policers_register(devlink,
1302 &policer_item->policer, 1);
1303 if (err)
1304 goto err_trap_policer_register;
1305 }
1306
1307 return 0;
1308
1309 err_trap_policer_register:
1310 for (i--; i >= 0; i--) {
1311 policer_item = &trap->policer_items_arr[i];
1312 devl_trap_policers_unregister(devlink,
1313 &policer_item->policer, 1);
1314 }
1315 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1316 return err;
1317 }
1318
1319 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp)
1320 {
1321 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1322 const struct mlxsw_sp_trap_policer_item *policer_item;
1323 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1324 int i;
1325
1326 for (i = trap->policers_count - 1; i >= 0; i--) {
1327 policer_item = &trap->policer_items_arr[i];
1328 devl_trap_policers_unregister(devlink,
1329 &policer_item->policer, 1);
1330 }
1331 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1332 }
1333
1334 static int mlxsw_sp_trap_group_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1335 {
1336 size_t common_groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr);
1337 const struct mlxsw_sp_trap_group_item *spec_group_items_arr;
1338 size_t elem_size = sizeof(struct mlxsw_sp_trap_group_item);
1339 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1340 size_t groups_count, spec_groups_count;
1341 int err;
1342
1343 err = mlxsw_sp->trap_ops->groups_init(mlxsw_sp, &spec_group_items_arr,
1344 &spec_groups_count);
1345 if (err)
1346 return err;
1347
1348
1349
1350
1351 groups_count = common_groups_count + spec_groups_count;
1352 trap->group_items_arr = kcalloc(groups_count, elem_size, GFP_KERNEL);
1353 if (!trap->group_items_arr)
1354 return -ENOMEM;
1355
1356 memcpy(trap->group_items_arr, mlxsw_sp_trap_group_items_arr,
1357 elem_size * common_groups_count);
1358 memcpy(trap->group_items_arr + common_groups_count,
1359 spec_group_items_arr, elem_size * spec_groups_count);
1360
1361 trap->groups_count = groups_count;
1362
1363 return 0;
1364 }
1365
1366 static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1367 {
1368 kfree(mlxsw_sp->trap->group_items_arr);
1369 }
1370
1371 static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp)
1372 {
1373 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1374 const struct mlxsw_sp_trap_group_item *group_item;
1375 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1376 int err, i;
1377
1378 err = mlxsw_sp_trap_group_items_arr_init(mlxsw_sp);
1379 if (err)
1380 return err;
1381
1382 for (i = 0; i < trap->groups_count; i++) {
1383 group_item = &trap->group_items_arr[i];
1384 err = devl_trap_groups_register(devlink, &group_item->group, 1);
1385 if (err)
1386 goto err_trap_group_register;
1387 }
1388
1389 return 0;
1390
1391 err_trap_group_register:
1392 for (i--; i >= 0; i--) {
1393 group_item = &trap->group_items_arr[i];
1394 devl_trap_groups_unregister(devlink, &group_item->group, 1);
1395 }
1396 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1397 return err;
1398 }
1399
1400 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp)
1401 {
1402 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1403 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1404 int i;
1405
1406 for (i = trap->groups_count - 1; i >= 0; i--) {
1407 const struct mlxsw_sp_trap_group_item *group_item;
1408
1409 group_item = &trap->group_items_arr[i];
1410 devl_trap_groups_unregister(devlink, &group_item->group, 1);
1411 }
1412 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1413 }
1414
1415 static bool
1416 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener)
1417 {
1418 return listener->trap_id != 0;
1419 }
1420
1421 static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1422 {
1423 size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr);
1424 const struct mlxsw_sp_trap_item *spec_trap_items_arr;
1425 size_t elem_size = sizeof(struct mlxsw_sp_trap_item);
1426 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1427 size_t traps_count, spec_traps_count;
1428 int err;
1429
1430 err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr,
1431 &spec_traps_count);
1432 if (err)
1433 return err;
1434
1435
1436
1437
1438 traps_count = common_traps_count + spec_traps_count;
1439 trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL);
1440 if (!trap->trap_items_arr)
1441 return -ENOMEM;
1442
1443 memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr,
1444 elem_size * common_traps_count);
1445 memcpy(trap->trap_items_arr + common_traps_count,
1446 spec_trap_items_arr, elem_size * spec_traps_count);
1447
1448 trap->traps_count = traps_count;
1449
1450 return 0;
1451 }
1452
1453 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1454 {
1455 kfree(mlxsw_sp->trap->trap_items_arr);
1456 }
1457
1458 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
1459 {
1460 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1461 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1462 const struct mlxsw_sp_trap_item *trap_item;
1463 int err, i;
1464
1465 err = mlxsw_sp_trap_items_arr_init(mlxsw_sp);
1466 if (err)
1467 return err;
1468
1469 for (i = 0; i < trap->traps_count; i++) {
1470 trap_item = &trap->trap_items_arr[i];
1471 err = devl_traps_register(devlink, &trap_item->trap, 1,
1472 mlxsw_sp);
1473 if (err)
1474 goto err_trap_register;
1475 }
1476
1477 return 0;
1478
1479 err_trap_register:
1480 for (i--; i >= 0; i--) {
1481 trap_item = &trap->trap_items_arr[i];
1482 devl_traps_unregister(devlink, &trap_item->trap, 1);
1483 }
1484 mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1485 return err;
1486 }
1487
1488 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
1489 {
1490 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1491 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1492 int i;
1493
1494 for (i = trap->traps_count - 1; i >= 0; i--) {
1495 const struct mlxsw_sp_trap_item *trap_item;
1496
1497 trap_item = &trap->trap_items_arr[i];
1498 devl_traps_unregister(devlink, &trap_item->trap, 1);
1499 }
1500 mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1501 }
1502
1503 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
1504 {
1505 int err;
1506
1507 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);
1508 if (err)
1509 return err;
1510
1511 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);
1512 if (err)
1513 return err;
1514
1515 err = mlxsw_sp_trap_policers_init(mlxsw_sp);
1516 if (err)
1517 return err;
1518
1519 err = mlxsw_sp_trap_groups_init(mlxsw_sp);
1520 if (err)
1521 goto err_trap_groups_init;
1522
1523 err = mlxsw_sp_traps_init(mlxsw_sp);
1524 if (err)
1525 goto err_traps_init;
1526
1527 return 0;
1528
1529 err_traps_init:
1530 mlxsw_sp_trap_groups_fini(mlxsw_sp);
1531 err_trap_groups_init:
1532 mlxsw_sp_trap_policers_fini(mlxsw_sp);
1533 return err;
1534 }
1535
1536 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
1537 {
1538 mlxsw_sp_traps_fini(mlxsw_sp);
1539 mlxsw_sp_trap_groups_fini(mlxsw_sp);
1540 mlxsw_sp_trap_policers_fini(mlxsw_sp);
1541 }
1542
1543 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
1544 const struct devlink_trap *trap, void *trap_ctx)
1545 {
1546 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1547 const struct mlxsw_sp_trap_item *trap_item;
1548 int i;
1549
1550 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1551 if (WARN_ON(!trap_item))
1552 return -EINVAL;
1553
1554 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1555 const struct mlxsw_listener *listener;
1556 int err;
1557
1558 listener = &trap_item->listeners_arr[i];
1559 if (!mlxsw_sp_trap_listener_is_valid(listener))
1560 continue;
1561 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
1562 if (err)
1563 return err;
1564 }
1565
1566 return 0;
1567 }
1568
1569 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
1570 const struct devlink_trap *trap, void *trap_ctx)
1571 {
1572 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1573 const struct mlxsw_sp_trap_item *trap_item;
1574 int i;
1575
1576 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1577 if (WARN_ON(!trap_item))
1578 return;
1579
1580 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) {
1581 const struct mlxsw_listener *listener;
1582
1583 listener = &trap_item->listeners_arr[i];
1584 if (!mlxsw_sp_trap_listener_is_valid(listener))
1585 continue;
1586 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
1587 }
1588 }
1589
1590 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
1591 const struct devlink_trap *trap,
1592 enum devlink_trap_action action,
1593 struct netlink_ext_ack *extack)
1594 {
1595 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1596 const struct mlxsw_sp_trap_item *trap_item;
1597 int i;
1598
1599 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1600 if (WARN_ON(!trap_item))
1601 return -EINVAL;
1602
1603 if (trap_item->is_source) {
1604 NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported");
1605 return -EOPNOTSUPP;
1606 }
1607
1608 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1609 const struct mlxsw_listener *listener;
1610 bool enabled;
1611 int err;
1612
1613 listener = &trap_item->listeners_arr[i];
1614 if (!mlxsw_sp_trap_listener_is_valid(listener))
1615 continue;
1616
1617 switch (action) {
1618 case DEVLINK_TRAP_ACTION_DROP:
1619 enabled = false;
1620 break;
1621 case DEVLINK_TRAP_ACTION_TRAP:
1622 enabled = true;
1623 break;
1624 default:
1625 return -EINVAL;
1626 }
1627 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);
1628 if (err)
1629 return err;
1630 }
1631
1632 return 0;
1633 }
1634
1635 static int
1636 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1637 const struct devlink_trap_group *group,
1638 u32 policer_id, struct netlink_ext_ack *extack)
1639 {
1640 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1641 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
1642 const struct mlxsw_sp_trap_group_item *group_item;
1643 char htgt_pl[MLXSW_REG_HTGT_LEN];
1644
1645 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id);
1646 if (WARN_ON(!group_item))
1647 return -EINVAL;
1648
1649 if (group_item->fixed_policer && policer_id != group->init_policer_id) {
1650 NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported");
1651 return -EOPNOTSUPP;
1652 }
1653
1654 if (policer_id) {
1655 struct mlxsw_sp_trap_policer_item *policer_item;
1656
1657 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,
1658 policer_id);
1659 if (WARN_ON(!policer_item))
1660 return -EINVAL;
1661 hw_policer_id = policer_item->hw_id;
1662 }
1663
1664 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id,
1665 group_item->priority, group_item->priority);
1666 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
1667 }
1668
1669 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1670 const struct devlink_trap_group *group)
1671 {
1672 return __mlxsw_sp_trap_group_init(mlxsw_core, group,
1673 group->init_policer_id, NULL);
1674 }
1675
1676 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
1677 const struct devlink_trap_group *group,
1678 const struct devlink_trap_policer *policer,
1679 struct netlink_ext_ack *extack)
1680 {
1681 u32 policer_id = policer ? policer->id : 0;
1682
1683 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id,
1684 extack);
1685 }
1686
1687 static int
1688 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp,
1689 struct mlxsw_sp_trap_policer_item *policer_item)
1690 {
1691 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1692 u16 hw_id;
1693
1694
1695
1696
1697
1698 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1699 if (WARN_ON(hw_id == trap->max_policers))
1700 return -ENOBUFS;
1701
1702 __set_bit(hw_id, trap->policers_usage);
1703 policer_item->hw_id = hw_id;
1704
1705 return 0;
1706 }
1707
1708 static void
1709 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,
1710 struct mlxsw_sp_trap_policer_item *policer_item)
1711 {
1712 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);
1713 }
1714
1715 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,
1716 struct netlink_ext_ack *extack)
1717 {
1718 int bs = fls64(burst) - 1;
1719
1720 if (burst != (BIT_ULL(bs))) {
1721 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
1722 return -EINVAL;
1723 }
1724
1725 *p_burst_size = bs;
1726
1727 return 0;
1728 }
1729
1730 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,
1731 u64 rate, u64 burst, bool clear_counter,
1732 struct netlink_ext_ack *extack)
1733 {
1734 char qpcr_pl[MLXSW_REG_QPCR_LEN];
1735 u8 burst_size;
1736 int err;
1737
1738 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);
1739 if (err)
1740 return err;
1741
1742 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,
1743 rate, burst_size);
1744 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);
1745 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1746 }
1747
1748 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
1749 const struct devlink_trap_policer *policer)
1750 {
1751 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1752 struct mlxsw_sp_trap_policer_item *policer_item;
1753 int err;
1754
1755 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1756 if (WARN_ON(!policer_item))
1757 return -EINVAL;
1758
1759 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item);
1760 if (err)
1761 return err;
1762
1763 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1764 policer->init_rate,
1765 policer->init_burst, true, NULL);
1766 if (err)
1767 goto err_trap_policer_set;
1768
1769 return 0;
1770
1771 err_trap_policer_set:
1772 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1773 return err;
1774 }
1775
1776 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,
1777 const struct devlink_trap_policer *policer)
1778 {
1779 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1780 struct mlxsw_sp_trap_policer_item *policer_item;
1781
1782 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1783 if (WARN_ON(!policer_item))
1784 return;
1785
1786 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1787 }
1788
1789 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,
1790 const struct devlink_trap_policer *policer,
1791 u64 rate, u64 burst,
1792 struct netlink_ext_ack *extack)
1793 {
1794 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1795 struct mlxsw_sp_trap_policer_item *policer_item;
1796
1797 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1798 if (WARN_ON(!policer_item))
1799 return -EINVAL;
1800
1801 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1802 rate, burst, false, extack);
1803 }
1804
1805 int
1806 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
1807 const struct devlink_trap_policer *policer,
1808 u64 *p_drops)
1809 {
1810 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1811 struct mlxsw_sp_trap_policer_item *policer_item;
1812 char qpcr_pl[MLXSW_REG_QPCR_LEN];
1813 int err;
1814
1815 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1816 if (WARN_ON(!policer_item))
1817 return -EINVAL;
1818
1819 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,
1820 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);
1821 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1822 if (err)
1823 return err;
1824
1825 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
1826
1827 return 0;
1828 }
1829
1830 int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id,
1831 bool *p_enabled, u16 *p_hw_id)
1832 {
1833 struct mlxsw_sp_trap_policer_item *pol_item;
1834 struct mlxsw_sp_trap_group_item *gr_item;
1835 u32 pol_id;
1836
1837 gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id);
1838 if (!gr_item)
1839 return -ENOENT;
1840
1841 pol_id = gr_item->group.init_policer_id;
1842 if (!pol_id) {
1843 *p_enabled = false;
1844 return 0;
1845 }
1846
1847 pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id);
1848 if (WARN_ON(!pol_item))
1849 return -ENOENT;
1850
1851 *p_enabled = true;
1852 *p_hw_id = pol_item->hw_id;
1853 return 0;
1854 }
1855
1856 static const struct mlxsw_sp_trap_group_item
1857 mlxsw_sp1_trap_group_items_arr[] = {
1858 {
1859 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1860 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1861 .priority = 0,
1862 },
1863 };
1864
1865 static const struct mlxsw_sp_trap_item
1866 mlxsw_sp1_trap_items_arr[] = {
1867 {
1868 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1869 MIRROR),
1870 .listeners_arr = {
1871 MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE,
1872 MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD),
1873 },
1874 },
1875 };
1876
1877 static int
1878 mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1879 const struct mlxsw_sp_trap_group_item **arr,
1880 size_t *p_groups_count)
1881 {
1882 *arr = mlxsw_sp1_trap_group_items_arr;
1883 *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr);
1884
1885 return 0;
1886 }
1887
1888 static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp,
1889 const struct mlxsw_sp_trap_item **arr,
1890 size_t *p_traps_count)
1891 {
1892 *arr = mlxsw_sp1_trap_items_arr;
1893 *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr);
1894
1895 return 0;
1896 }
1897
1898 const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = {
1899 .groups_init = mlxsw_sp1_trap_groups_init,
1900 .traps_init = mlxsw_sp1_traps_init,
1901 };
1902
1903 static const struct mlxsw_sp_trap_group_item
1904 mlxsw_sp2_trap_group_items_arr[] = {
1905 {
1906 .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20),
1907 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,
1908 .priority = 0,
1909 .fixed_policer = true,
1910 },
1911 {
1912 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1913 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1914 .priority = 0,
1915 .fixed_policer = true,
1916 },
1917 };
1918
1919 static const struct mlxsw_sp_trap_item
1920 mlxsw_sp2_trap_items_arr[] = {
1921 {
1922 .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP),
1923 .listeners_arr = {
1924 MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED),
1925 },
1926 .is_source = true,
1927 },
1928 {
1929 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1930 MIRROR),
1931 .listeners_arr = {
1932 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1,
1933 SP_PKT_SAMPLE,
1934 MLXSW_SP_MIRROR_REASON_INGRESS),
1935 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1,
1936 SP_PKT_SAMPLE,
1937 MLXSW_SP_MIRROR_REASON_EGRESS),
1938 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1,
1939 SP_PKT_SAMPLE,
1940 MLXSW_SP_MIRROR_REASON_POLICY_ENGINE),
1941 },
1942 },
1943 };
1944
1945 static int
1946 mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1947 const struct mlxsw_sp_trap_group_item **arr,
1948 size_t *p_groups_count)
1949 {
1950 *arr = mlxsw_sp2_trap_group_items_arr;
1951 *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr);
1952
1953 return 0;
1954 }
1955
1956 static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp,
1957 const struct mlxsw_sp_trap_item **arr,
1958 size_t *p_traps_count)
1959 {
1960 *arr = mlxsw_sp2_trap_items_arr;
1961 *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr);
1962
1963 return 0;
1964 }
1965
1966 const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = {
1967 .groups_init = mlxsw_sp2_trap_groups_init,
1968 .traps_init = mlxsw_sp2_traps_init,
1969 };