1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */ |
3 | |
4 | #include <net/devlink.h> |
5 | |
6 | #include "prestera_devlink.h" |
7 | #include "prestera_hw.h" |
8 | |
9 | /* All driver-specific traps must be documented in |
10 | * Documentation/networking/devlink/prestera.rst |
11 | */ |
12 | enum { |
13 | DEVLINK_PRESTERA_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, |
14 | DEVLINK_PRESTERA_TRAP_ID_ARP_BC, |
15 | DEVLINK_PRESTERA_TRAP_ID_IS_IS, |
16 | DEVLINK_PRESTERA_TRAP_ID_OSPF, |
17 | DEVLINK_PRESTERA_TRAP_ID_IP_BC_MAC, |
18 | DEVLINK_PRESTERA_TRAP_ID_ROUTER_MC, |
19 | DEVLINK_PRESTERA_TRAP_ID_VRRP, |
20 | DEVLINK_PRESTERA_TRAP_ID_DHCP, |
21 | DEVLINK_PRESTERA_TRAP_ID_MAC_TO_ME, |
22 | DEVLINK_PRESTERA_TRAP_ID_IPV4_OPTIONS, |
23 | DEVLINK_PRESTERA_TRAP_ID_IP_DEFAULT_ROUTE, |
24 | DEVLINK_PRESTERA_TRAP_ID_IP_TO_ME, |
25 | DEVLINK_PRESTERA_TRAP_ID_IPV4_ICMP_REDIRECT, |
26 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_0, |
27 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_1, |
28 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_2, |
29 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_3, |
30 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_4, |
31 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_5, |
32 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_6, |
33 | DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_7, |
34 | DEVLINK_PRESTERA_TRAP_ID_BGP, |
35 | DEVLINK_PRESTERA_TRAP_ID_SSH, |
36 | DEVLINK_PRESTERA_TRAP_ID_TELNET, |
37 | DEVLINK_PRESTERA_TRAP_ID_ICMP, |
38 | DEVLINK_PRESTERA_TRAP_ID_MET_RED, |
39 | DEVLINK_PRESTERA_TRAP_ID_IP_SIP_IS_ZERO, |
40 | DEVLINK_PRESTERA_TRAP_ID_IP_UC_DIP_DA_MISMATCH, |
41 | DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IPV4_HDR, |
42 | DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IP_ADDR, |
43 | DEVLINK_PRESTERA_TRAP_ID_INVALID_SA, |
44 | DEVLINK_PRESTERA_TRAP_ID_LOCAL_PORT, |
45 | DEVLINK_PRESTERA_TRAP_ID_PORT_NO_VLAN, |
46 | DEVLINK_PRESTERA_TRAP_ID_RXDMA_DROP, |
47 | }; |
48 | |
49 | #define DEVLINK_PRESTERA_TRAP_NAME_ARP_BC \ |
50 | "arp_bc" |
51 | #define DEVLINK_PRESTERA_TRAP_NAME_IS_IS \ |
52 | "is_is" |
53 | #define DEVLINK_PRESTERA_TRAP_NAME_OSPF \ |
54 | "ospf" |
55 | #define DEVLINK_PRESTERA_TRAP_NAME_IP_BC_MAC \ |
56 | "ip_bc_mac" |
57 | #define DEVLINK_PRESTERA_TRAP_NAME_ROUTER_MC \ |
58 | "router_mc" |
59 | #define DEVLINK_PRESTERA_TRAP_NAME_VRRP \ |
60 | "vrrp" |
61 | #define DEVLINK_PRESTERA_TRAP_NAME_DHCP \ |
62 | "dhcp" |
63 | #define DEVLINK_PRESTERA_TRAP_NAME_MAC_TO_ME \ |
64 | "mac_to_me" |
65 | #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_OPTIONS \ |
66 | "ipv4_options" |
67 | #define DEVLINK_PRESTERA_TRAP_NAME_IP_DEFAULT_ROUTE \ |
68 | "ip_default_route" |
69 | #define DEVLINK_PRESTERA_TRAP_NAME_IP_TO_ME \ |
70 | "ip_to_me" |
71 | #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_ICMP_REDIRECT \ |
72 | "ipv4_icmp_redirect" |
73 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_0 \ |
74 | "acl_code_0" |
75 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_1 \ |
76 | "acl_code_1" |
77 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_2 \ |
78 | "acl_code_2" |
79 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_3 \ |
80 | "acl_code_3" |
81 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_4 \ |
82 | "acl_code_4" |
83 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_5 \ |
84 | "acl_code_5" |
85 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_6 \ |
86 | "acl_code_6" |
87 | #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_7 \ |
88 | "acl_code_7" |
89 | #define DEVLINK_PRESTERA_TRAP_NAME_BGP \ |
90 | "bgp" |
91 | #define DEVLINK_PRESTERA_TRAP_NAME_SSH \ |
92 | "ssh" |
93 | #define DEVLINK_PRESTERA_TRAP_NAME_TELNET \ |
94 | "telnet" |
95 | #define DEVLINK_PRESTERA_TRAP_NAME_ICMP \ |
96 | "icmp" |
97 | #define DEVLINK_PRESTERA_TRAP_NAME_RXDMA_DROP \ |
98 | "rxdma_drop" |
99 | #define DEVLINK_PRESTERA_TRAP_NAME_PORT_NO_VLAN \ |
100 | "port_no_vlan" |
101 | #define DEVLINK_PRESTERA_TRAP_NAME_LOCAL_PORT \ |
102 | "local_port" |
103 | #define DEVLINK_PRESTERA_TRAP_NAME_INVALID_SA \ |
104 | "invalid_sa" |
105 | #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IP_ADDR \ |
106 | "illegal_ip_addr" |
107 | #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IPV4_HDR \ |
108 | "illegal_ipv4_hdr" |
109 | #define DEVLINK_PRESTERA_TRAP_NAME_IP_UC_DIP_DA_MISMATCH \ |
110 | "ip_uc_dip_da_mismatch" |
111 | #define DEVLINK_PRESTERA_TRAP_NAME_IP_SIP_IS_ZERO \ |
112 | "ip_sip_is_zero" |
113 | #define DEVLINK_PRESTERA_TRAP_NAME_MET_RED \ |
114 | "met_red" |
115 | |
116 | struct prestera_trap { |
117 | struct devlink_trap trap; |
118 | u8 cpu_code; |
119 | }; |
120 | |
121 | struct prestera_trap_item { |
122 | enum devlink_trap_action action; |
123 | void *trap_ctx; |
124 | }; |
125 | |
126 | struct prestera_trap_data { |
127 | struct prestera_switch *sw; |
128 | struct prestera_trap_item *trap_items_arr; |
129 | u32 traps_count; |
130 | }; |
131 | |
132 | #define PRESTERA_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT |
133 | |
134 | #define PRESTERA_TRAP_CONTROL(_id, _group_id, _action) \ |
135 | DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ |
136 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
137 | PRESTERA_TRAP_METADATA) |
138 | |
139 | #define PRESTERA_TRAP_DRIVER_CONTROL(_id, _group_id) \ |
140 | DEVLINK_TRAP_DRIVER(CONTROL, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \ |
141 | DEVLINK_PRESTERA_TRAP_NAME_##_id, \ |
142 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
143 | PRESTERA_TRAP_METADATA) |
144 | |
145 | #define PRESTERA_TRAP_EXCEPTION(_id, _group_id) \ |
146 | DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ |
147 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
148 | PRESTERA_TRAP_METADATA) |
149 | |
150 | #define PRESTERA_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ |
151 | DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \ |
152 | DEVLINK_PRESTERA_TRAP_NAME_##_id, \ |
153 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
154 | PRESTERA_TRAP_METADATA) |
155 | |
156 | #define PRESTERA_TRAP_DRIVER_DROP(_id, _group_id) \ |
157 | DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_PRESTERA_TRAP_ID_##_id, \ |
158 | DEVLINK_PRESTERA_TRAP_NAME_##_id, \ |
159 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
160 | PRESTERA_TRAP_METADATA) |
161 | |
162 | static const struct devlink_trap_group prestera_trap_groups_arr[] = { |
163 | /* No policer is associated with following groups (policerid == 0)*/ |
164 | DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), |
165 | DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 0), |
166 | DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 0), |
167 | DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 0), |
168 | DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 0), |
169 | DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 0), |
170 | DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), |
171 | DEVLINK_TRAP_GROUP_GENERIC(OSPF, 0), |
172 | DEVLINK_TRAP_GROUP_GENERIC(STP, 0), |
173 | DEVLINK_TRAP_GROUP_GENERIC(LACP, 0), |
174 | DEVLINK_TRAP_GROUP_GENERIC(LLDP, 0), |
175 | DEVLINK_TRAP_GROUP_GENERIC(VRRP, 0), |
176 | DEVLINK_TRAP_GROUP_GENERIC(DHCP, 0), |
177 | DEVLINK_TRAP_GROUP_GENERIC(BGP, 0), |
178 | DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 0), |
179 | DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 0), |
180 | }; |
181 | |
182 | /* Initialize trap list, as well as associate CPU code with them. */ |
183 | static struct prestera_trap prestera_trap_items_arr[] = { |
184 | { |
185 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ARP_BC, NEIGH_DISCOVERY), |
186 | .cpu_code = 5, |
187 | }, |
188 | { |
189 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(IS_IS, LOCAL_DELIVERY), |
190 | .cpu_code = 13, |
191 | }, |
192 | { |
193 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(OSPF, OSPF), |
194 | .cpu_code = 16, |
195 | }, |
196 | { |
197 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_BC_MAC, LOCAL_DELIVERY), |
198 | .cpu_code = 19, |
199 | }, |
200 | { |
201 | .trap = PRESTERA_TRAP_CONTROL(STP, STP, TRAP), |
202 | .cpu_code = 26, |
203 | }, |
204 | { |
205 | .trap = PRESTERA_TRAP_CONTROL(LACP, LACP, TRAP), |
206 | .cpu_code = 27, |
207 | }, |
208 | { |
209 | .trap = PRESTERA_TRAP_CONTROL(LLDP, LLDP, TRAP), |
210 | .cpu_code = 28, |
211 | }, |
212 | { |
213 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ROUTER_MC, LOCAL_DELIVERY), |
214 | .cpu_code = 29, |
215 | }, |
216 | { |
217 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(VRRP, VRRP), |
218 | .cpu_code = 30, |
219 | }, |
220 | { |
221 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(DHCP, DHCP), |
222 | .cpu_code = 33, |
223 | }, |
224 | { |
225 | .trap = PRESTERA_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS), |
226 | .cpu_code = 63, |
227 | }, |
228 | { |
229 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(MAC_TO_ME, LOCAL_DELIVERY), |
230 | .cpu_code = 65, |
231 | }, |
232 | { |
233 | .trap = PRESTERA_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), |
234 | .cpu_code = 133, |
235 | }, |
236 | { |
237 | .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_OPTIONS, |
238 | L3_EXCEPTIONS), |
239 | .cpu_code = 141, |
240 | }, |
241 | { |
242 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_DEFAULT_ROUTE, |
243 | LOCAL_DELIVERY), |
244 | .cpu_code = 160, |
245 | }, |
246 | { |
247 | .trap = PRESTERA_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY, |
248 | TRAP), |
249 | .cpu_code = 161, |
250 | }, |
251 | { |
252 | .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_ICMP_REDIRECT, |
253 | L3_EXCEPTIONS), |
254 | .cpu_code = 180, |
255 | }, |
256 | { |
257 | .trap = PRESTERA_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY, |
258 | TRAP), |
259 | .cpu_code = 188, |
260 | }, |
261 | { |
262 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_0, ACL_TRAP), |
263 | .cpu_code = 192, |
264 | }, |
265 | { |
266 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_1, ACL_TRAP), |
267 | .cpu_code = 193, |
268 | }, |
269 | { |
270 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_2, ACL_TRAP), |
271 | .cpu_code = 194, |
272 | }, |
273 | { |
274 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_3, ACL_TRAP), |
275 | .cpu_code = 195, |
276 | }, |
277 | { |
278 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_4, ACL_TRAP), |
279 | .cpu_code = 196, |
280 | }, |
281 | { |
282 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_5, ACL_TRAP), |
283 | .cpu_code = 197, |
284 | }, |
285 | { |
286 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_6, ACL_TRAP), |
287 | .cpu_code = 198, |
288 | }, |
289 | { |
290 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_7, ACL_TRAP), |
291 | .cpu_code = 199, |
292 | }, |
293 | { |
294 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(BGP, BGP), |
295 | .cpu_code = 206, |
296 | }, |
297 | { |
298 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(SSH, LOCAL_DELIVERY), |
299 | .cpu_code = 207, |
300 | }, |
301 | { |
302 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(TELNET, LOCAL_DELIVERY), |
303 | .cpu_code = 208, |
304 | }, |
305 | { |
306 | .trap = PRESTERA_TRAP_DRIVER_CONTROL(ICMP, LOCAL_DELIVERY), |
307 | .cpu_code = 209, |
308 | }, |
309 | { |
310 | .trap = PRESTERA_TRAP_DRIVER_DROP(RXDMA_DROP, BUFFER_DROPS), |
311 | .cpu_code = 37, |
312 | }, |
313 | { |
314 | .trap = PRESTERA_TRAP_DRIVER_DROP(PORT_NO_VLAN, L2_DROPS), |
315 | .cpu_code = 39, |
316 | }, |
317 | { |
318 | .trap = PRESTERA_TRAP_DRIVER_DROP(LOCAL_PORT, L2_DROPS), |
319 | .cpu_code = 56, |
320 | }, |
321 | { |
322 | .trap = PRESTERA_TRAP_DRIVER_DROP(INVALID_SA, L2_DROPS), |
323 | .cpu_code = 60, |
324 | }, |
325 | { |
326 | .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IP_ADDR, L3_DROPS), |
327 | .cpu_code = 136, |
328 | }, |
329 | { |
330 | .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IPV4_HDR, L3_DROPS), |
331 | .cpu_code = 137, |
332 | }, |
333 | { |
334 | .trap = PRESTERA_TRAP_DRIVER_DROP(IP_UC_DIP_DA_MISMATCH, |
335 | L3_DROPS), |
336 | .cpu_code = 138, |
337 | }, |
338 | { |
339 | .trap = PRESTERA_TRAP_DRIVER_DROP(IP_SIP_IS_ZERO, L3_DROPS), |
340 | .cpu_code = 145, |
341 | }, |
342 | { |
343 | .trap = PRESTERA_TRAP_DRIVER_DROP(MET_RED, BUFFER_DROPS), |
344 | .cpu_code = 185, |
345 | }, |
346 | }; |
347 | |
348 | static int prestera_drop_counter_get(struct devlink *devlink, |
349 | const struct devlink_trap *trap, |
350 | u64 *p_drops); |
351 | |
352 | static int prestera_dl_info_get(struct devlink *dl, |
353 | struct devlink_info_req *req, |
354 | struct netlink_ext_ack *extack) |
355 | { |
356 | struct prestera_switch *sw = devlink_priv(devlink: dl); |
357 | char buf[16]; |
358 | |
359 | snprintf(buf, size: sizeof(buf), fmt: "%d.%d.%d" , |
360 | sw->dev->fw_rev.maj, |
361 | sw->dev->fw_rev.min, |
362 | sw->dev->fw_rev.sub); |
363 | |
364 | return devlink_info_version_running_put(req, |
365 | DEVLINK_INFO_VERSION_GENERIC_FW, |
366 | version_value: buf); |
367 | } |
368 | |
369 | static int prestera_trap_init(struct devlink *devlink, |
370 | const struct devlink_trap *trap, void *trap_ctx); |
371 | |
372 | static int prestera_trap_action_set(struct devlink *devlink, |
373 | const struct devlink_trap *trap, |
374 | enum devlink_trap_action action, |
375 | struct netlink_ext_ack *extack); |
376 | |
377 | static const struct devlink_ops prestera_dl_ops = { |
378 | .info_get = prestera_dl_info_get, |
379 | .trap_init = prestera_trap_init, |
380 | .trap_action_set = prestera_trap_action_set, |
381 | .trap_drop_counter_get = prestera_drop_counter_get, |
382 | }; |
383 | |
384 | struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev) |
385 | { |
386 | struct devlink *dl; |
387 | |
388 | dl = devlink_alloc(ops: &prestera_dl_ops, priv_size: sizeof(struct prestera_switch), |
389 | dev: dev->dev); |
390 | |
391 | return devlink_priv(devlink: dl); |
392 | } |
393 | |
394 | void prestera_devlink_free(struct prestera_switch *sw) |
395 | { |
396 | struct devlink *dl = priv_to_devlink(priv: sw); |
397 | |
398 | devlink_free(devlink: dl); |
399 | } |
400 | |
401 | void prestera_devlink_register(struct prestera_switch *sw) |
402 | { |
403 | struct devlink *dl = priv_to_devlink(priv: sw); |
404 | |
405 | devlink_register(devlink: dl); |
406 | } |
407 | |
408 | void prestera_devlink_unregister(struct prestera_switch *sw) |
409 | { |
410 | struct devlink *dl = priv_to_devlink(priv: sw); |
411 | |
412 | devlink_unregister(devlink: dl); |
413 | } |
414 | |
415 | int prestera_devlink_port_register(struct prestera_port *port) |
416 | { |
417 | struct prestera_switch *sw = port->sw; |
418 | struct devlink *dl = priv_to_devlink(priv: sw); |
419 | struct devlink_port_attrs attrs = {}; |
420 | int err; |
421 | |
422 | attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; |
423 | attrs.phys.port_number = port->fp_id; |
424 | attrs.switch_id.id_len = sizeof(sw->id); |
425 | memcpy(attrs.switch_id.id, &sw->id, attrs.switch_id.id_len); |
426 | |
427 | devlink_port_attrs_set(devlink_port: &port->dl_port, devlink_port_attrs: &attrs); |
428 | |
429 | err = devlink_port_register(devlink: dl, devlink_port: &port->dl_port, port_index: port->fp_id); |
430 | if (err) { |
431 | dev_err(prestera_dev(sw), "devlink_port_register failed: %d\n" , err); |
432 | return err; |
433 | } |
434 | |
435 | return 0; |
436 | } |
437 | |
438 | void prestera_devlink_port_unregister(struct prestera_port *port) |
439 | { |
440 | devlink_port_unregister(devlink_port: &port->dl_port); |
441 | } |
442 | |
443 | int prestera_devlink_traps_register(struct prestera_switch *sw) |
444 | { |
445 | const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr); |
446 | const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr); |
447 | struct devlink *devlink = priv_to_devlink(priv: sw); |
448 | struct prestera_trap_data *trap_data; |
449 | struct prestera_trap *prestera_trap; |
450 | int err, i; |
451 | |
452 | trap_data = kzalloc(size: sizeof(*trap_data), GFP_KERNEL); |
453 | if (!trap_data) |
454 | return -ENOMEM; |
455 | |
456 | trap_data->trap_items_arr = kcalloc(n: traps_count, |
457 | size: sizeof(struct prestera_trap_item), |
458 | GFP_KERNEL); |
459 | if (!trap_data->trap_items_arr) { |
460 | err = -ENOMEM; |
461 | goto err_trap_items_alloc; |
462 | } |
463 | |
464 | trap_data->sw = sw; |
465 | trap_data->traps_count = traps_count; |
466 | sw->trap_data = trap_data; |
467 | |
468 | err = devlink_trap_groups_register(devlink, groups: prestera_trap_groups_arr, |
469 | groups_count); |
470 | if (err) |
471 | goto err_groups_register; |
472 | |
473 | for (i = 0; i < traps_count; i++) { |
474 | prestera_trap = &prestera_trap_items_arr[i]; |
475 | err = devlink_traps_register(devlink, traps: &prestera_trap->trap, traps_count: 1, |
476 | priv: sw); |
477 | if (err) |
478 | goto err_trap_register; |
479 | } |
480 | |
481 | return 0; |
482 | |
483 | err_trap_register: |
484 | for (i--; i >= 0; i--) { |
485 | prestera_trap = &prestera_trap_items_arr[i]; |
486 | devlink_traps_unregister(devlink, traps: &prestera_trap->trap, traps_count: 1); |
487 | } |
488 | devlink_trap_groups_unregister(devlink, groups: prestera_trap_groups_arr, |
489 | groups_count); |
490 | err_groups_register: |
491 | kfree(objp: trap_data->trap_items_arr); |
492 | err_trap_items_alloc: |
493 | kfree(objp: trap_data); |
494 | return err; |
495 | } |
496 | |
497 | static struct prestera_trap_item * |
498 | prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code) |
499 | { |
500 | struct prestera_trap_data *trap_data = sw->trap_data; |
501 | struct prestera_trap *prestera_trap; |
502 | int i; |
503 | |
504 | for (i = 0; i < trap_data->traps_count; i++) { |
505 | prestera_trap = &prestera_trap_items_arr[i]; |
506 | if (cpu_code == prestera_trap->cpu_code) |
507 | return &trap_data->trap_items_arr[i]; |
508 | } |
509 | |
510 | return NULL; |
511 | } |
512 | |
513 | void prestera_devlink_trap_report(struct prestera_port *port, |
514 | struct sk_buff *skb, u8 cpu_code) |
515 | { |
516 | struct prestera_trap_item *trap_item; |
517 | struct devlink *devlink; |
518 | |
519 | devlink = port->dl_port.devlink; |
520 | |
521 | trap_item = prestera_get_trap_item_by_cpu_code(sw: port->sw, cpu_code); |
522 | if (unlikely(!trap_item)) |
523 | return; |
524 | |
525 | devlink_trap_report(devlink, skb, trap_ctx: trap_item->trap_ctx, |
526 | in_devlink_port: &port->dl_port, NULL); |
527 | } |
528 | |
529 | static struct prestera_trap_item * |
530 | prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id) |
531 | { |
532 | struct prestera_trap_data *trap_data = sw->trap_data; |
533 | int i; |
534 | |
535 | for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) { |
536 | if (prestera_trap_items_arr[i].trap.id == trap_id) |
537 | return &trap_data->trap_items_arr[i]; |
538 | } |
539 | |
540 | return NULL; |
541 | } |
542 | |
543 | static int prestera_trap_init(struct devlink *devlink, |
544 | const struct devlink_trap *trap, void *trap_ctx) |
545 | { |
546 | struct prestera_switch *sw = devlink_priv(devlink); |
547 | struct prestera_trap_item *trap_item; |
548 | |
549 | trap_item = prestera_devlink_trap_item_lookup(sw, trap_id: trap->id); |
550 | if (WARN_ON(!trap_item)) |
551 | return -EINVAL; |
552 | |
553 | trap_item->trap_ctx = trap_ctx; |
554 | trap_item->action = trap->init_action; |
555 | |
556 | return 0; |
557 | } |
558 | |
559 | static int prestera_trap_action_set(struct devlink *devlink, |
560 | const struct devlink_trap *trap, |
561 | enum devlink_trap_action action, |
562 | struct netlink_ext_ack *extack) |
563 | { |
564 | /* Currently, driver does not support trap action altering */ |
565 | return -EOPNOTSUPP; |
566 | } |
567 | |
568 | static int prestera_drop_counter_get(struct devlink *devlink, |
569 | const struct devlink_trap *trap, |
570 | u64 *p_drops) |
571 | { |
572 | struct prestera_switch *sw = devlink_priv(devlink); |
573 | enum prestera_hw_cpu_code_cnt_t cpu_code_type = |
574 | PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP; |
575 | struct prestera_trap *prestera_trap = |
576 | container_of(trap, struct prestera_trap, trap); |
577 | |
578 | return prestera_hw_cpu_code_counters_get(sw, code: prestera_trap->cpu_code, |
579 | counter_type: cpu_code_type, packet_count: p_drops); |
580 | } |
581 | |
582 | void prestera_devlink_traps_unregister(struct prestera_switch *sw) |
583 | { |
584 | struct prestera_trap_data *trap_data = sw->trap_data; |
585 | struct devlink *dl = priv_to_devlink(priv: sw); |
586 | const struct devlink_trap *trap; |
587 | int i; |
588 | |
589 | for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) { |
590 | trap = &prestera_trap_items_arr[i].trap; |
591 | devlink_traps_unregister(devlink: dl, traps: trap, traps_count: 1); |
592 | } |
593 | |
594 | devlink_trap_groups_unregister(devlink: dl, groups: prestera_trap_groups_arr, |
595 | ARRAY_SIZE(prestera_trap_groups_arr)); |
596 | kfree(objp: trap_data->trap_items_arr); |
597 | kfree(objp: trap_data); |
598 | } |
599 | |