1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
5 #include <net/devlink.h>
6 #include <uapi/linux/devlink.h>
12 /* All driver-specific traps must be documented in
13 * Documentation/networking/devlink/mlxsw.rst
16 DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
17 DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
18 DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
21 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
23 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
26 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
28 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
30 static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port,
33 #define MLXSW_SP_TRAP_DROP(_id, _group_id) \
34 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
35 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
36 MLXSW_SP_TRAP_METADATA)
38 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \
39 DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \
40 DEVLINK_MLXSW_TRAP_NAME_##_id, \
41 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
42 MLXSW_SP_TRAP_METADATA)
44 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \
45 DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
46 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
47 MLXSW_SP_TRAP_METADATA)
49 #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \
50 MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \
51 false, SP_##_group_id, DISCARD)
53 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \
54 MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \
55 _action, false, SP_##_group_id, DISCARD)
57 static struct devlink_trap mlxsw_sp_traps_arr[] = {
58 MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
59 MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
60 MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
61 MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
62 MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
63 MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
64 MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
65 MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
66 MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
67 MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
68 MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
69 MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
70 MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
71 MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
72 MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS),
73 MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS),
74 MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS),
75 MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
76 MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS),
77 MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS),
78 MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS),
79 MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS),
80 MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS),
81 MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
82 MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
83 MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
86 static struct mlxsw_listener mlxsw_sp_listeners_arr[] = {
87 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
88 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS),
89 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
90 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
91 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
92 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
93 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
94 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
95 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS),
96 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS),
97 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
98 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
99 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
100 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS),
101 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS),
102 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS),
103 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS),
104 MLXSW_SP_RXL_EXCEPTION(MTUERROR, ROUTER_EXP, TRAP_TO_CPU),
105 MLXSW_SP_RXL_EXCEPTION(TTLERROR, ROUTER_EXP, TRAP_TO_CPU),
106 MLXSW_SP_RXL_EXCEPTION(RPF, RPF, TRAP_TO_CPU),
107 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, REMOTE_ROUTE, TRAP_TO_CPU),
108 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, HOST_MISS, TRAP_TO_CPU),
109 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, HOST_MISS, TRAP_TO_CPU),
110 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, REMOTE_ROUTE,
111 TRAP_EXCEPTION_TO_CPU),
112 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, ROUTER_EXP,
113 TRAP_EXCEPTION_TO_CPU),
114 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, ROUTER_EXP,
115 TRAP_EXCEPTION_TO_CPU),
116 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
117 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
118 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
121 /* Mapping between hardware trap and devlink trap. Multiple hardware traps can
122 * be mapped to the same devlink trap. Order is according to
123 * 'mlxsw_sp_listeners_arr'.
125 static u16 mlxsw_sp_listener_devlink_map[] = {
126 DEVLINK_TRAP_GENERIC_ID_SMAC_MC,
127 DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH,
128 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
129 DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER,
130 DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
131 DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
132 DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER,
133 DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE,
134 DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET,
135 DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC,
136 DEVLINK_TRAP_GENERIC_ID_DIP_LB,
137 DEVLINK_TRAP_GENERIC_ID_SIP_MC,
138 DEVLINK_TRAP_GENERIC_ID_SIP_LB,
139 DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR,
140 DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC,
141 DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE,
142 DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
143 DEVLINK_TRAP_GENERIC_ID_MTU_ERROR,
144 DEVLINK_TRAP_GENERIC_ID_TTL_ERROR,
145 DEVLINK_TRAP_GENERIC_ID_RPF,
146 DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE,
147 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
148 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
149 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
150 DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS,
151 DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS,
152 DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
153 DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
154 DEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE,
157 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
159 struct mlxsw_sp_port *mlxsw_sp_port)
161 struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
163 if (unlikely(!mlxsw_sp_port)) {
164 dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
170 skb->dev = mlxsw_sp_port->dev;
172 pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
173 u64_stats_update_begin(&pcpu_stats->syncp);
174 pcpu_stats->rx_packets++;
175 pcpu_stats->rx_bytes += skb->len;
176 u64_stats_update_end(&pcpu_stats->syncp);
178 skb->protocol = eth_type_trans(skb, skb->dev);
183 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
186 struct devlink_port *in_devlink_port;
187 struct mlxsw_sp_port *mlxsw_sp_port;
188 struct mlxsw_sp *mlxsw_sp;
189 struct devlink *devlink;
191 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
192 mlxsw_sp_port = mlxsw_sp->ports[local_port];
194 if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port))
197 devlink = priv_to_devlink(mlxsw_sp->core);
198 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
200 skb_push(skb, ETH_HLEN);
201 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port);
205 static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port,
208 struct devlink_port *in_devlink_port;
209 struct mlxsw_sp_port *mlxsw_sp_port;
210 struct mlxsw_sp *mlxsw_sp;
211 struct devlink *devlink;
213 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
214 mlxsw_sp_port = mlxsw_sp->ports[local_port];
216 if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port))
219 devlink = priv_to_devlink(mlxsw_sp->core);
220 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
222 skb_push(skb, ETH_HLEN);
223 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port);
224 skb_pull(skb, ETH_HLEN);
225 skb->offload_fwd_mark = 1;
226 netif_receive_skb(skb);
229 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
231 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
233 if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) !=
234 ARRAY_SIZE(mlxsw_sp_listeners_arr)))
237 return devlink_traps_register(devlink, mlxsw_sp_traps_arr,
238 ARRAY_SIZE(mlxsw_sp_traps_arr),
242 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
244 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
246 devlink_traps_unregister(devlink, mlxsw_sp_traps_arr,
247 ARRAY_SIZE(mlxsw_sp_traps_arr));
250 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
251 const struct devlink_trap *trap, void *trap_ctx)
255 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
256 struct mlxsw_listener *listener;
259 if (mlxsw_sp_listener_devlink_map[i] != trap->id)
261 listener = &mlxsw_sp_listeners_arr[i];
263 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
271 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
272 const struct devlink_trap *trap, void *trap_ctx)
276 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
277 struct mlxsw_listener *listener;
279 if (mlxsw_sp_listener_devlink_map[i] != trap->id)
281 listener = &mlxsw_sp_listeners_arr[i];
283 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
287 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
288 const struct devlink_trap *trap,
289 enum devlink_trap_action action)
293 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
294 enum mlxsw_reg_hpkt_action hw_action;
295 struct mlxsw_listener *listener;
298 if (mlxsw_sp_listener_devlink_map[i] != trap->id)
300 listener = &mlxsw_sp_listeners_arr[i];
303 case DEVLINK_TRAP_ACTION_DROP:
304 hw_action = MLXSW_REG_HPKT_ACTION_SET_FW_DEFAULT;
306 case DEVLINK_TRAP_ACTION_TRAP:
307 hw_action = MLXSW_REG_HPKT_ACTION_TRAP_EXCEPTION_TO_CPU;
313 err = mlxsw_core_trap_action_set(mlxsw_core, listener,
322 #define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1)
325 mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp,
326 const struct devlink_trap_group *group)
328 enum mlxsw_reg_qpcr_ir_units ir_units;
329 char qpcr_pl[MLXSW_REG_QPCR_LEN];
336 case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:/* fall through */
337 case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS:
338 policer_id = MLXSW_SP_DISCARD_POLICER_ID;
339 ir_units = MLXSW_REG_QPCR_IR_UNITS_M;
341 rate = 10 * 1024; /* 10Kpps */
348 mlxsw_reg_qpcr_pack(qpcr_pl, policer_id, ir_units, is_bytes, rate,
350 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
354 __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp,
355 const struct devlink_trap_group *group)
357 char htgt_pl[MLXSW_REG_HTGT_LEN];
358 u8 priority, tc, group_id;
362 case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS:
363 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS;
364 policer_id = MLXSW_SP_DISCARD_POLICER_ID;
368 case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:
369 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS;
370 policer_id = MLXSW_SP_DISCARD_POLICER_ID;
378 mlxsw_reg_htgt_pack(htgt_pl, group_id, policer_id, priority, tc);
379 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);
382 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
383 const struct devlink_trap_group *group)
385 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
388 err = mlxsw_sp_trap_group_policer_init(mlxsw_sp, group);
392 err = __mlxsw_sp_trap_group_init(mlxsw_sp, group);